1*9821f1d3SAlan Somers /*- 2*9821f1d3SAlan Somers * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3*9821f1d3SAlan Somers * 4*9821f1d3SAlan Somers * Copyright (c) 2019 The FreeBSD Foundation 5*9821f1d3SAlan Somers * 6*9821f1d3SAlan Somers * This software was developed by BFF Storage Systems, LLC under sponsorship 7*9821f1d3SAlan Somers * from the FreeBSD Foundation. 8*9821f1d3SAlan Somers * 9*9821f1d3SAlan Somers * Redistribution and use in source and binary forms, with or without 10*9821f1d3SAlan Somers * modification, are permitted provided that the following conditions 11*9821f1d3SAlan Somers * are met: 12*9821f1d3SAlan Somers * 1. Redistributions of source code must retain the above copyright 13*9821f1d3SAlan Somers * notice, this list of conditions and the following disclaimer. 14*9821f1d3SAlan Somers * 2. Redistributions in binary form must reproduce the above copyright 15*9821f1d3SAlan Somers * notice, this list of conditions and the following disclaimer in the 16*9821f1d3SAlan Somers * documentation and/or other materials provided with the distribution. 17*9821f1d3SAlan Somers * 18*9821f1d3SAlan Somers * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19*9821f1d3SAlan Somers * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20*9821f1d3SAlan Somers * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21*9821f1d3SAlan Somers * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22*9821f1d3SAlan Somers * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23*9821f1d3SAlan Somers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24*9821f1d3SAlan Somers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25*9821f1d3SAlan Somers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26*9821f1d3SAlan Somers * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27*9821f1d3SAlan Somers * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28*9821f1d3SAlan Somers * SUCH DAMAGE. 29*9821f1d3SAlan Somers */ 30*9821f1d3SAlan Somers 31*9821f1d3SAlan Somers extern "C" { 32*9821f1d3SAlan Somers #include <sys/param.h> 33*9821f1d3SAlan Somers 34*9821f1d3SAlan Somers #include <sys/mount.h> 35*9821f1d3SAlan Somers #include <sys/stat.h> 36*9821f1d3SAlan Somers #include <sys/uio.h> 37*9821f1d3SAlan Somers #include <sys/user.h> 38*9821f1d3SAlan Somers 39*9821f1d3SAlan Somers #include <fcntl.h> 40*9821f1d3SAlan Somers #include <libutil.h> 41*9821f1d3SAlan Somers #include <pthread.h> 42*9821f1d3SAlan Somers #include <signal.h> 43*9821f1d3SAlan Somers #include <stdlib.h> 44*9821f1d3SAlan Somers #include <unistd.h> 45*9821f1d3SAlan Somers 46*9821f1d3SAlan Somers #include "mntopts.h" // for build_iovec 47*9821f1d3SAlan Somers } 48*9821f1d3SAlan Somers 49*9821f1d3SAlan Somers #include <gtest/gtest.h> 50*9821f1d3SAlan Somers 51*9821f1d3SAlan Somers #include "mockfs.hh" 52*9821f1d3SAlan Somers 53*9821f1d3SAlan Somers using namespace testing; 54*9821f1d3SAlan Somers 55*9821f1d3SAlan Somers int verbosity = 0; 56*9821f1d3SAlan Somers static sig_atomic_t quit = 0; 57*9821f1d3SAlan Somers 58*9821f1d3SAlan Somers const char* opcode2opname(uint32_t opcode) 59*9821f1d3SAlan Somers { 60*9821f1d3SAlan Somers const int NUM_OPS = 39; 61*9821f1d3SAlan Somers const char* table[NUM_OPS] = { 62*9821f1d3SAlan Somers "Unknown (opcode 0)", 63*9821f1d3SAlan Somers "LOOKUP", 64*9821f1d3SAlan Somers "FORGET", 65*9821f1d3SAlan Somers "GETATTR", 66*9821f1d3SAlan Somers "SETATTR", 67*9821f1d3SAlan Somers "READLINK", 68*9821f1d3SAlan Somers "SYMLINK", 69*9821f1d3SAlan Somers "Unknown (opcode 7)", 70*9821f1d3SAlan Somers "MKNOD", 71*9821f1d3SAlan Somers "MKDIR", 72*9821f1d3SAlan Somers "UNLINK", 73*9821f1d3SAlan Somers "RMDIR", 74*9821f1d3SAlan Somers "RENAME", 75*9821f1d3SAlan Somers "LINK", 76*9821f1d3SAlan Somers "OPEN", 77*9821f1d3SAlan Somers "READ", 78*9821f1d3SAlan Somers "WRITE", 79*9821f1d3SAlan Somers "STATFS", 80*9821f1d3SAlan Somers "RELEASE", 81*9821f1d3SAlan Somers "Unknown (opcode 19)", 82*9821f1d3SAlan Somers "FSYNC", 83*9821f1d3SAlan Somers "SETXATTR", 84*9821f1d3SAlan Somers "GETXATTR", 85*9821f1d3SAlan Somers "LISTXATTR", 86*9821f1d3SAlan Somers "REMOVEXATTR", 87*9821f1d3SAlan Somers "FLUSH", 88*9821f1d3SAlan Somers "INIT", 89*9821f1d3SAlan Somers "OPENDIR", 90*9821f1d3SAlan Somers "READDIR", 91*9821f1d3SAlan Somers "RELEASEDIR", 92*9821f1d3SAlan Somers "FSYNCDIR", 93*9821f1d3SAlan Somers "GETLK", 94*9821f1d3SAlan Somers "SETLK", 95*9821f1d3SAlan Somers "SETLKW", 96*9821f1d3SAlan Somers "ACCESS", 97*9821f1d3SAlan Somers "CREATE", 98*9821f1d3SAlan Somers "INTERRUPT", 99*9821f1d3SAlan Somers "BMAP", 100*9821f1d3SAlan Somers "DESTROY" 101*9821f1d3SAlan Somers }; 102*9821f1d3SAlan Somers if (opcode >= NUM_OPS) 103*9821f1d3SAlan Somers return ("Unknown (opcode > max)"); 104*9821f1d3SAlan Somers else 105*9821f1d3SAlan Somers return (table[opcode]); 106*9821f1d3SAlan Somers } 107*9821f1d3SAlan Somers 108*9821f1d3SAlan Somers ProcessMockerT 109*9821f1d3SAlan Somers ReturnErrno(int error) 110*9821f1d3SAlan Somers { 111*9821f1d3SAlan Somers return([=](auto in, auto &out) { 112*9821f1d3SAlan Somers auto out0 = new mockfs_buf_out; 113*9821f1d3SAlan Somers out0->header.unique = in->header.unique; 114*9821f1d3SAlan Somers out0->header.error = -error; 115*9821f1d3SAlan Somers out0->header.len = sizeof(out0->header); 116*9821f1d3SAlan Somers out.push_back(out0); 117*9821f1d3SAlan Somers }); 118*9821f1d3SAlan Somers } 119*9821f1d3SAlan Somers 120*9821f1d3SAlan Somers /* Helper function used for returning negative cache entries for LOOKUP */ 121*9821f1d3SAlan Somers ProcessMockerT 122*9821f1d3SAlan Somers ReturnNegativeCache(const struct timespec *entry_valid) 123*9821f1d3SAlan Somers { 124*9821f1d3SAlan Somers return([=](auto in, auto &out) { 125*9821f1d3SAlan Somers /* nodeid means ENOENT and cache it */ 126*9821f1d3SAlan Somers auto out0 = new mockfs_buf_out; 127*9821f1d3SAlan Somers out0->body.entry.nodeid = 0; 128*9821f1d3SAlan Somers out0->header.unique = in->header.unique; 129*9821f1d3SAlan Somers out0->header.error = 0; 130*9821f1d3SAlan Somers out0->body.entry.entry_valid = entry_valid->tv_sec; 131*9821f1d3SAlan Somers out0->body.entry.entry_valid_nsec = entry_valid->tv_nsec; 132*9821f1d3SAlan Somers SET_OUT_HEADER_LEN(out0, entry); 133*9821f1d3SAlan Somers out.push_back(out0); 134*9821f1d3SAlan Somers }); 135*9821f1d3SAlan Somers } 136*9821f1d3SAlan Somers 137*9821f1d3SAlan Somers ProcessMockerT 138*9821f1d3SAlan Somers ReturnImmediate(std::function<void(const struct mockfs_buf_in *in, 139*9821f1d3SAlan Somers struct mockfs_buf_out *out)> f) 140*9821f1d3SAlan Somers { 141*9821f1d3SAlan Somers return([=](auto in, auto &out) { 142*9821f1d3SAlan Somers auto out0 = new mockfs_buf_out; 143*9821f1d3SAlan Somers out0->header.unique = in->header.unique; 144*9821f1d3SAlan Somers f(in, out0); 145*9821f1d3SAlan Somers out.push_back(out0); 146*9821f1d3SAlan Somers }); 147*9821f1d3SAlan Somers } 148*9821f1d3SAlan Somers 149*9821f1d3SAlan Somers void sigint_handler(int __unused sig) { 150*9821f1d3SAlan Somers quit = 1; 151*9821f1d3SAlan Somers } 152*9821f1d3SAlan Somers 153*9821f1d3SAlan Somers void debug_fuseop(const mockfs_buf_in *in) 154*9821f1d3SAlan Somers { 155*9821f1d3SAlan Somers printf("%-11s ino=%2lu", opcode2opname(in->header.opcode), 156*9821f1d3SAlan Somers in->header.nodeid); 157*9821f1d3SAlan Somers if (verbosity > 1) { 158*9821f1d3SAlan Somers printf(" uid=%5u gid=%5u pid=%5u unique=%lu len=%u", 159*9821f1d3SAlan Somers in->header.uid, in->header.gid, in->header.pid, 160*9821f1d3SAlan Somers in->header.unique, in->header.len); 161*9821f1d3SAlan Somers } 162*9821f1d3SAlan Somers switch (in->header.opcode) { 163*9821f1d3SAlan Somers case FUSE_FLUSH: 164*9821f1d3SAlan Somers printf(" lock_owner=%lu", in->body.flush.lock_owner); 165*9821f1d3SAlan Somers break; 166*9821f1d3SAlan Somers case FUSE_FORGET: 167*9821f1d3SAlan Somers printf(" nlookup=%lu", in->body.forget.nlookup); 168*9821f1d3SAlan Somers break; 169*9821f1d3SAlan Somers case FUSE_FSYNC: 170*9821f1d3SAlan Somers printf(" flags=%#x", in->body.fsync.fsync_flags); 171*9821f1d3SAlan Somers break; 172*9821f1d3SAlan Somers case FUSE_FSYNCDIR: 173*9821f1d3SAlan Somers printf(" flags=%#x", in->body.fsyncdir.fsync_flags); 174*9821f1d3SAlan Somers break; 175*9821f1d3SAlan Somers case FUSE_LOOKUP: 176*9821f1d3SAlan Somers printf(" %s", in->body.lookup); 177*9821f1d3SAlan Somers break; 178*9821f1d3SAlan Somers case FUSE_OPEN: 179*9821f1d3SAlan Somers printf(" flags=%#x mode=%#o", 180*9821f1d3SAlan Somers in->body.open.flags, in->body.open.mode); 181*9821f1d3SAlan Somers break; 182*9821f1d3SAlan Somers case FUSE_OPENDIR: 183*9821f1d3SAlan Somers printf(" flags=%#x mode=%#o", 184*9821f1d3SAlan Somers in->body.opendir.flags, in->body.opendir.mode); 185*9821f1d3SAlan Somers break; 186*9821f1d3SAlan Somers case FUSE_READ: 187*9821f1d3SAlan Somers printf(" offset=%lu size=%u", in->body.read.offset, 188*9821f1d3SAlan Somers in->body.read.size); 189*9821f1d3SAlan Somers break; 190*9821f1d3SAlan Somers case FUSE_READDIR: 191*9821f1d3SAlan Somers printf(" offset=%lu size=%u", in->body.readdir.offset, 192*9821f1d3SAlan Somers in->body.readdir.size); 193*9821f1d3SAlan Somers break; 194*9821f1d3SAlan Somers case FUSE_RELEASE: 195*9821f1d3SAlan Somers printf(" flags=%#x lock_owner=%lu", 196*9821f1d3SAlan Somers in->body.release.flags, 197*9821f1d3SAlan Somers in->body.release.lock_owner); 198*9821f1d3SAlan Somers break; 199*9821f1d3SAlan Somers case FUSE_SETATTR: 200*9821f1d3SAlan Somers if (verbosity <= 1) { 201*9821f1d3SAlan Somers printf(" valid=%#x", in->body.setattr.valid); 202*9821f1d3SAlan Somers break; 203*9821f1d3SAlan Somers } 204*9821f1d3SAlan Somers if (in->body.setattr.valid & FATTR_MODE) 205*9821f1d3SAlan Somers printf(" mode=%#o", in->body.setattr.mode); 206*9821f1d3SAlan Somers if (in->body.setattr.valid & FATTR_UID) 207*9821f1d3SAlan Somers printf(" uid=%u", in->body.setattr.uid); 208*9821f1d3SAlan Somers if (in->body.setattr.valid & FATTR_GID) 209*9821f1d3SAlan Somers printf(" gid=%u", in->body.setattr.gid); 210*9821f1d3SAlan Somers if (in->body.setattr.valid & FATTR_SIZE) 211*9821f1d3SAlan Somers printf(" size=%zu", in->body.setattr.size); 212*9821f1d3SAlan Somers if (in->body.setattr.valid & FATTR_ATIME) 213*9821f1d3SAlan Somers printf(" atime=%zu.%u", 214*9821f1d3SAlan Somers in->body.setattr.atime, 215*9821f1d3SAlan Somers in->body.setattr.atimensec); 216*9821f1d3SAlan Somers if (in->body.setattr.valid & FATTR_MTIME) 217*9821f1d3SAlan Somers printf(" mtime=%zu.%u", 218*9821f1d3SAlan Somers in->body.setattr.mtime, 219*9821f1d3SAlan Somers in->body.setattr.mtimensec); 220*9821f1d3SAlan Somers if (in->body.setattr.valid & FATTR_FH) 221*9821f1d3SAlan Somers printf(" fh=%zu", in->body.setattr.fh); 222*9821f1d3SAlan Somers break; 223*9821f1d3SAlan Somers case FUSE_SETXATTR: 224*9821f1d3SAlan Somers /* 225*9821f1d3SAlan Somers * In theory neither the xattr name and value need be 226*9821f1d3SAlan Somers * ASCII, but in this test suite they always are. 227*9821f1d3SAlan Somers */ 228*9821f1d3SAlan Somers { 229*9821f1d3SAlan Somers const char *attr = (const char*)in->body.bytes + 230*9821f1d3SAlan Somers sizeof(fuse_setxattr_in); 231*9821f1d3SAlan Somers const char *v = attr + strlen(attr) + 1; 232*9821f1d3SAlan Somers printf(" %s=%s", attr, v); 233*9821f1d3SAlan Somers } 234*9821f1d3SAlan Somers break; 235*9821f1d3SAlan Somers case FUSE_WRITE: 236*9821f1d3SAlan Somers printf(" offset=%lu size=%u flags=%u", 237*9821f1d3SAlan Somers in->body.write.offset, in->body.write.size, 238*9821f1d3SAlan Somers in->body.write.write_flags); 239*9821f1d3SAlan Somers break; 240*9821f1d3SAlan Somers default: 241*9821f1d3SAlan Somers break; 242*9821f1d3SAlan Somers } 243*9821f1d3SAlan Somers printf("\n"); 244*9821f1d3SAlan Somers } 245*9821f1d3SAlan Somers 246*9821f1d3SAlan Somers MockFS::MockFS(int max_readahead, bool push_symlinks_in, 247*9821f1d3SAlan Somers bool default_permissions, uint32_t flags) 248*9821f1d3SAlan Somers { 249*9821f1d3SAlan Somers struct iovec *iov = NULL; 250*9821f1d3SAlan Somers int iovlen = 0; 251*9821f1d3SAlan Somers char fdstr[15]; 252*9821f1d3SAlan Somers 253*9821f1d3SAlan Somers m_daemon_id = NULL; 254*9821f1d3SAlan Somers m_maxreadahead = max_readahead; 255*9821f1d3SAlan Somers quit = 0; 256*9821f1d3SAlan Somers 257*9821f1d3SAlan Somers /* 258*9821f1d3SAlan Somers * Kyua sets pwd to a testcase-unique tempdir; no need to use 259*9821f1d3SAlan Somers * mkdtemp 260*9821f1d3SAlan Somers */ 261*9821f1d3SAlan Somers /* 262*9821f1d3SAlan Somers * googletest doesn't allow ASSERT_ in constructors, so we must throw 263*9821f1d3SAlan Somers * instead. 264*9821f1d3SAlan Somers */ 265*9821f1d3SAlan Somers if (mkdir("mountpoint" , 0644) && errno != EEXIST) 266*9821f1d3SAlan Somers throw(std::system_error(errno, std::system_category(), 267*9821f1d3SAlan Somers "Couldn't make mountpoint directory")); 268*9821f1d3SAlan Somers 269*9821f1d3SAlan Somers m_fuse_fd = open("/dev/fuse", O_RDWR); 270*9821f1d3SAlan Somers if (m_fuse_fd < 0) 271*9821f1d3SAlan Somers throw(std::system_error(errno, std::system_category(), 272*9821f1d3SAlan Somers "Couldn't open /dev/fuse")); 273*9821f1d3SAlan Somers sprintf(fdstr, "%d", m_fuse_fd); 274*9821f1d3SAlan Somers 275*9821f1d3SAlan Somers m_pid = getpid(); 276*9821f1d3SAlan Somers 277*9821f1d3SAlan Somers build_iovec(&iov, &iovlen, "fstype", __DECONST(void *, "fusefs"), -1); 278*9821f1d3SAlan Somers build_iovec(&iov, &iovlen, "fspath", 279*9821f1d3SAlan Somers __DECONST(void *, "mountpoint"), -1); 280*9821f1d3SAlan Somers build_iovec(&iov, &iovlen, "from", __DECONST(void *, "/dev/fuse"), -1); 281*9821f1d3SAlan Somers build_iovec(&iov, &iovlen, "fd", fdstr, -1); 282*9821f1d3SAlan Somers if (push_symlinks_in) { 283*9821f1d3SAlan Somers const bool trueval = true; 284*9821f1d3SAlan Somers build_iovec(&iov, &iovlen, "push_symlinks_in", 285*9821f1d3SAlan Somers __DECONST(void*, &trueval), sizeof(bool)); 286*9821f1d3SAlan Somers } 287*9821f1d3SAlan Somers if (default_permissions) { 288*9821f1d3SAlan Somers const bool trueval = true; 289*9821f1d3SAlan Somers build_iovec(&iov, &iovlen, "default_permissions", 290*9821f1d3SAlan Somers __DECONST(void*, &trueval), sizeof(bool)); 291*9821f1d3SAlan Somers } 292*9821f1d3SAlan Somers if (nmount(iov, iovlen, 0)) 293*9821f1d3SAlan Somers throw(std::system_error(errno, std::system_category(), 294*9821f1d3SAlan Somers "Couldn't mount filesystem")); 295*9821f1d3SAlan Somers 296*9821f1d3SAlan Somers // Setup default handler 297*9821f1d3SAlan Somers ON_CALL(*this, process(_, _)) 298*9821f1d3SAlan Somers .WillByDefault(Invoke(this, &MockFS::process_default)); 299*9821f1d3SAlan Somers 300*9821f1d3SAlan Somers init(flags); 301*9821f1d3SAlan Somers signal(SIGUSR1, sigint_handler); 302*9821f1d3SAlan Somers if (pthread_create(&m_daemon_id, NULL, service, (void*)this)) 303*9821f1d3SAlan Somers throw(std::system_error(errno, std::system_category(), 304*9821f1d3SAlan Somers "Couldn't Couldn't start fuse thread")); 305*9821f1d3SAlan Somers } 306*9821f1d3SAlan Somers 307*9821f1d3SAlan Somers MockFS::~MockFS() { 308*9821f1d3SAlan Somers kill_daemon(); 309*9821f1d3SAlan Somers ::unmount("mountpoint", MNT_FORCE); 310*9821f1d3SAlan Somers if (m_daemon_id != NULL) { 311*9821f1d3SAlan Somers pthread_join(m_daemon_id, NULL); 312*9821f1d3SAlan Somers m_daemon_id = NULL; 313*9821f1d3SAlan Somers } 314*9821f1d3SAlan Somers rmdir("mountpoint"); 315*9821f1d3SAlan Somers } 316*9821f1d3SAlan Somers 317*9821f1d3SAlan Somers void MockFS::init(uint32_t flags) { 318*9821f1d3SAlan Somers mockfs_buf_in *in; 319*9821f1d3SAlan Somers mockfs_buf_out *out; 320*9821f1d3SAlan Somers 321*9821f1d3SAlan Somers in = (mockfs_buf_in*) malloc(sizeof(*in)); 322*9821f1d3SAlan Somers ASSERT_TRUE(in != NULL); 323*9821f1d3SAlan Somers out = (mockfs_buf_out*) malloc(sizeof(*out)); 324*9821f1d3SAlan Somers ASSERT_TRUE(out != NULL); 325*9821f1d3SAlan Somers 326*9821f1d3SAlan Somers read_request(in); 327*9821f1d3SAlan Somers ASSERT_EQ(FUSE_INIT, in->header.opcode); 328*9821f1d3SAlan Somers 329*9821f1d3SAlan Somers memset(out, 0, sizeof(*out)); 330*9821f1d3SAlan Somers out->header.unique = in->header.unique; 331*9821f1d3SAlan Somers out->header.error = 0; 332*9821f1d3SAlan Somers out->body.init.major = FUSE_KERNEL_VERSION; 333*9821f1d3SAlan Somers out->body.init.minor = FUSE_KERNEL_MINOR_VERSION; 334*9821f1d3SAlan Somers out->body.init.flags = in->body.init.flags & flags; 335*9821f1d3SAlan Somers 336*9821f1d3SAlan Somers /* 337*9821f1d3SAlan Somers * The default max_write is set to this formula in libfuse, though 338*9821f1d3SAlan Somers * individual filesystems can lower it. The "- 4096" was added in 339*9821f1d3SAlan Somers * commit 154ffe2, with the commit message "fix". 340*9821f1d3SAlan Somers */ 341*9821f1d3SAlan Somers uint32_t default_max_write = 32 * getpagesize() + 0x1000 - 4096; 342*9821f1d3SAlan Somers /* For testing purposes, it should be distinct from MAXPHYS */ 343*9821f1d3SAlan Somers m_max_write = MIN(default_max_write, MAXPHYS / 2); 344*9821f1d3SAlan Somers out->body.init.max_write = m_max_write; 345*9821f1d3SAlan Somers 346*9821f1d3SAlan Somers out->body.init.max_readahead = m_maxreadahead; 347*9821f1d3SAlan Somers SET_OUT_HEADER_LEN(out, init); 348*9821f1d3SAlan Somers write(m_fuse_fd, out, out->header.len); 349*9821f1d3SAlan Somers 350*9821f1d3SAlan Somers free(in); 351*9821f1d3SAlan Somers } 352*9821f1d3SAlan Somers 353*9821f1d3SAlan Somers void MockFS::kill_daemon() { 354*9821f1d3SAlan Somers if (m_daemon_id != NULL) { 355*9821f1d3SAlan Somers pthread_kill(m_daemon_id, SIGUSR1); 356*9821f1d3SAlan Somers // Closing the /dev/fuse file descriptor first allows unmount 357*9821f1d3SAlan Somers // to succeed even if the daemon doesn't correctly respond to 358*9821f1d3SAlan Somers // commands during the unmount sequence. 359*9821f1d3SAlan Somers close(m_fuse_fd); 360*9821f1d3SAlan Somers } 361*9821f1d3SAlan Somers } 362*9821f1d3SAlan Somers 363*9821f1d3SAlan Somers void MockFS::loop() { 364*9821f1d3SAlan Somers mockfs_buf_in *in; 365*9821f1d3SAlan Somers std::vector<mockfs_buf_out*> out; 366*9821f1d3SAlan Somers 367*9821f1d3SAlan Somers in = (mockfs_buf_in*) malloc(sizeof(*in)); 368*9821f1d3SAlan Somers ASSERT_TRUE(in != NULL); 369*9821f1d3SAlan Somers while (!quit) { 370*9821f1d3SAlan Somers bzero(in, sizeof(*in)); 371*9821f1d3SAlan Somers read_request(in); 372*9821f1d3SAlan Somers if (quit) 373*9821f1d3SAlan Somers break; 374*9821f1d3SAlan Somers if (verbosity > 0) 375*9821f1d3SAlan Somers debug_fuseop(in); 376*9821f1d3SAlan Somers if (pid_ok((pid_t)in->header.pid)) { 377*9821f1d3SAlan Somers process(in, out); 378*9821f1d3SAlan Somers } else { 379*9821f1d3SAlan Somers /* 380*9821f1d3SAlan Somers * Reject any requests from unknown processes. Because 381*9821f1d3SAlan Somers * we actually do mount a filesystem, plenty of 382*9821f1d3SAlan Somers * unrelated system daemons may try to access it. 383*9821f1d3SAlan Somers */ 384*9821f1d3SAlan Somers process_default(in, out); 385*9821f1d3SAlan Somers } 386*9821f1d3SAlan Somers for (auto &it: out) { 387*9821f1d3SAlan Somers ASSERT_TRUE(write(m_fuse_fd, it, it->header.len) > 0 || 388*9821f1d3SAlan Somers errno == EAGAIN) 389*9821f1d3SAlan Somers << strerror(errno); 390*9821f1d3SAlan Somers delete it; 391*9821f1d3SAlan Somers } 392*9821f1d3SAlan Somers out.clear(); 393*9821f1d3SAlan Somers } 394*9821f1d3SAlan Somers free(in); 395*9821f1d3SAlan Somers } 396*9821f1d3SAlan Somers 397*9821f1d3SAlan Somers bool MockFS::pid_ok(pid_t pid) { 398*9821f1d3SAlan Somers if (pid == m_pid) { 399*9821f1d3SAlan Somers return (true); 400*9821f1d3SAlan Somers } else { 401*9821f1d3SAlan Somers struct kinfo_proc *ki; 402*9821f1d3SAlan Somers bool ok = false; 403*9821f1d3SAlan Somers 404*9821f1d3SAlan Somers ki = kinfo_getproc(pid); 405*9821f1d3SAlan Somers if (ki == NULL) 406*9821f1d3SAlan Somers return (false); 407*9821f1d3SAlan Somers /* 408*9821f1d3SAlan Somers * Allow access by the aio daemon processes so that our tests 409*9821f1d3SAlan Somers * can use aio functions 410*9821f1d3SAlan Somers */ 411*9821f1d3SAlan Somers if (0 == strncmp("aiod", ki->ki_comm, 4)) 412*9821f1d3SAlan Somers ok = true; 413*9821f1d3SAlan Somers free(ki); 414*9821f1d3SAlan Somers return (ok); 415*9821f1d3SAlan Somers } 416*9821f1d3SAlan Somers } 417*9821f1d3SAlan Somers 418*9821f1d3SAlan Somers void MockFS::process_default(const mockfs_buf_in *in, 419*9821f1d3SAlan Somers std::vector<mockfs_buf_out*> &out) 420*9821f1d3SAlan Somers { 421*9821f1d3SAlan Somers auto out0 = new mockfs_buf_out; 422*9821f1d3SAlan Somers out0->header.unique = in->header.unique; 423*9821f1d3SAlan Somers out0->header.error = -EOPNOTSUPP; 424*9821f1d3SAlan Somers out0->header.len = sizeof(out0->header); 425*9821f1d3SAlan Somers out.push_back(out0); 426*9821f1d3SAlan Somers } 427*9821f1d3SAlan Somers 428*9821f1d3SAlan Somers void MockFS::read_request(mockfs_buf_in *in) { 429*9821f1d3SAlan Somers ssize_t res; 430*9821f1d3SAlan Somers 431*9821f1d3SAlan Somers res = read(m_fuse_fd, in, sizeof(*in)); 432*9821f1d3SAlan Somers if (res < 0 && !quit) 433*9821f1d3SAlan Somers perror("read"); 434*9821f1d3SAlan Somers ASSERT_TRUE(res >= (ssize_t)sizeof(in->header) || quit); 435*9821f1d3SAlan Somers } 436*9821f1d3SAlan Somers 437*9821f1d3SAlan Somers void* MockFS::service(void *pthr_data) { 438*9821f1d3SAlan Somers MockFS *mock_fs = (MockFS*)pthr_data; 439*9821f1d3SAlan Somers 440*9821f1d3SAlan Somers mock_fs->loop(); 441*9821f1d3SAlan Somers 442*9821f1d3SAlan Somers return (NULL); 443*9821f1d3SAlan Somers } 444*9821f1d3SAlan Somers 445*9821f1d3SAlan Somers void MockFS::unmount() { 446*9821f1d3SAlan Somers ::unmount("mountpoint", 0); 447*9821f1d3SAlan Somers } 448