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. 299821f1d3SAlan Somers */ 309821f1d3SAlan Somers 319821f1d3SAlan Somers extern "C" { 329821f1d3SAlan Somers #include <sys/param.h> 339821f1d3SAlan Somers 349821f1d3SAlan Somers #include <sys/mount.h> 359821f1d3SAlan Somers #include <sys/stat.h> 369821f1d3SAlan Somers #include <sys/uio.h> 379821f1d3SAlan Somers #include <sys/user.h> 389821f1d3SAlan Somers 399821f1d3SAlan Somers #include <fcntl.h> 409821f1d3SAlan Somers #include <libutil.h> 419821f1d3SAlan Somers #include <pthread.h> 429821f1d3SAlan Somers #include <signal.h> 439821f1d3SAlan Somers #include <stdlib.h> 449821f1d3SAlan Somers #include <unistd.h> 459821f1d3SAlan Somers 469821f1d3SAlan Somers #include "mntopts.h" // for build_iovec 479821f1d3SAlan Somers } 489821f1d3SAlan Somers 499821f1d3SAlan Somers #include <gtest/gtest.h> 509821f1d3SAlan Somers 519821f1d3SAlan Somers #include "mockfs.hh" 529821f1d3SAlan Somers 539821f1d3SAlan Somers using namespace testing; 549821f1d3SAlan Somers 559821f1d3SAlan Somers int verbosity = 0; 569821f1d3SAlan Somers static sig_atomic_t quit = 0; 579821f1d3SAlan Somers 589821f1d3SAlan Somers const char* opcode2opname(uint32_t opcode) 599821f1d3SAlan Somers { 609821f1d3SAlan Somers const int NUM_OPS = 39; 619821f1d3SAlan Somers const char* table[NUM_OPS] = { 629821f1d3SAlan Somers "Unknown (opcode 0)", 639821f1d3SAlan Somers "LOOKUP", 649821f1d3SAlan Somers "FORGET", 659821f1d3SAlan Somers "GETATTR", 669821f1d3SAlan Somers "SETATTR", 679821f1d3SAlan Somers "READLINK", 689821f1d3SAlan Somers "SYMLINK", 699821f1d3SAlan Somers "Unknown (opcode 7)", 709821f1d3SAlan Somers "MKNOD", 719821f1d3SAlan Somers "MKDIR", 729821f1d3SAlan Somers "UNLINK", 739821f1d3SAlan Somers "RMDIR", 749821f1d3SAlan Somers "RENAME", 759821f1d3SAlan Somers "LINK", 769821f1d3SAlan Somers "OPEN", 779821f1d3SAlan Somers "READ", 789821f1d3SAlan Somers "WRITE", 799821f1d3SAlan Somers "STATFS", 809821f1d3SAlan Somers "RELEASE", 819821f1d3SAlan Somers "Unknown (opcode 19)", 829821f1d3SAlan Somers "FSYNC", 839821f1d3SAlan Somers "SETXATTR", 849821f1d3SAlan Somers "GETXATTR", 859821f1d3SAlan Somers "LISTXATTR", 869821f1d3SAlan Somers "REMOVEXATTR", 879821f1d3SAlan Somers "FLUSH", 889821f1d3SAlan Somers "INIT", 899821f1d3SAlan Somers "OPENDIR", 909821f1d3SAlan Somers "READDIR", 919821f1d3SAlan Somers "RELEASEDIR", 929821f1d3SAlan Somers "FSYNCDIR", 939821f1d3SAlan Somers "GETLK", 949821f1d3SAlan Somers "SETLK", 959821f1d3SAlan Somers "SETLKW", 969821f1d3SAlan Somers "ACCESS", 979821f1d3SAlan Somers "CREATE", 989821f1d3SAlan Somers "INTERRUPT", 999821f1d3SAlan Somers "BMAP", 1009821f1d3SAlan Somers "DESTROY" 1019821f1d3SAlan Somers }; 1029821f1d3SAlan Somers if (opcode >= NUM_OPS) 1039821f1d3SAlan Somers return ("Unknown (opcode > max)"); 1049821f1d3SAlan Somers else 1059821f1d3SAlan Somers return (table[opcode]); 1069821f1d3SAlan Somers } 1079821f1d3SAlan Somers 1089821f1d3SAlan Somers ProcessMockerT 1099821f1d3SAlan Somers ReturnErrno(int error) 1109821f1d3SAlan Somers { 1119821f1d3SAlan Somers return([=](auto in, auto &out) { 1129821f1d3SAlan Somers auto out0 = new mockfs_buf_out; 1139821f1d3SAlan Somers out0->header.unique = in->header.unique; 1149821f1d3SAlan Somers out0->header.error = -error; 1159821f1d3SAlan Somers out0->header.len = sizeof(out0->header); 1169821f1d3SAlan Somers out.push_back(out0); 1179821f1d3SAlan Somers }); 1189821f1d3SAlan Somers } 1199821f1d3SAlan Somers 1209821f1d3SAlan Somers /* Helper function used for returning negative cache entries for LOOKUP */ 1219821f1d3SAlan Somers ProcessMockerT 1229821f1d3SAlan Somers ReturnNegativeCache(const struct timespec *entry_valid) 1239821f1d3SAlan Somers { 1249821f1d3SAlan Somers return([=](auto in, auto &out) { 1259821f1d3SAlan Somers /* nodeid means ENOENT and cache it */ 1269821f1d3SAlan Somers auto out0 = new mockfs_buf_out; 1279821f1d3SAlan Somers out0->body.entry.nodeid = 0; 1289821f1d3SAlan Somers out0->header.unique = in->header.unique; 1299821f1d3SAlan Somers out0->header.error = 0; 1309821f1d3SAlan Somers out0->body.entry.entry_valid = entry_valid->tv_sec; 1319821f1d3SAlan Somers out0->body.entry.entry_valid_nsec = entry_valid->tv_nsec; 1329821f1d3SAlan Somers SET_OUT_HEADER_LEN(out0, entry); 1339821f1d3SAlan Somers out.push_back(out0); 1349821f1d3SAlan Somers }); 1359821f1d3SAlan Somers } 1369821f1d3SAlan Somers 1379821f1d3SAlan Somers ProcessMockerT 1389821f1d3SAlan Somers ReturnImmediate(std::function<void(const struct mockfs_buf_in *in, 1399821f1d3SAlan Somers struct mockfs_buf_out *out)> f) 1409821f1d3SAlan Somers { 1419821f1d3SAlan Somers return([=](auto in, auto &out) { 1429821f1d3SAlan Somers auto out0 = new mockfs_buf_out; 1439821f1d3SAlan Somers out0->header.unique = in->header.unique; 1449821f1d3SAlan Somers f(in, out0); 1459821f1d3SAlan Somers out.push_back(out0); 1469821f1d3SAlan Somers }); 1479821f1d3SAlan Somers } 1489821f1d3SAlan Somers 1499821f1d3SAlan Somers void sigint_handler(int __unused sig) { 1509821f1d3SAlan Somers quit = 1; 1519821f1d3SAlan Somers } 1529821f1d3SAlan Somers 1539821f1d3SAlan Somers void debug_fuseop(const mockfs_buf_in *in) 1549821f1d3SAlan Somers { 1559821f1d3SAlan Somers printf("%-11s ino=%2lu", opcode2opname(in->header.opcode), 1569821f1d3SAlan Somers in->header.nodeid); 1579821f1d3SAlan Somers if (verbosity > 1) { 1589821f1d3SAlan Somers printf(" uid=%5u gid=%5u pid=%5u unique=%lu len=%u", 1599821f1d3SAlan Somers in->header.uid, in->header.gid, in->header.pid, 1609821f1d3SAlan Somers in->header.unique, in->header.len); 1619821f1d3SAlan Somers } 1629821f1d3SAlan Somers switch (in->header.opcode) { 16319ef317dSAlan Somers const char *name, *value; 16419ef317dSAlan Somers 16519ef317dSAlan Somers case FUSE_CREATE: 16619ef317dSAlan Somers name = (const char*)in->body.bytes + 16719ef317dSAlan Somers sizeof(fuse_open_in); 16819ef317dSAlan Somers printf(" flags=%#x name=%s", 16919ef317dSAlan Somers in->body.open.flags, name); 17019ef317dSAlan Somers break; 1719821f1d3SAlan Somers case FUSE_FLUSH: 1729f10f423SAlan Somers printf(" fh=%#lx lock_owner=%lu", in->body.flush.fh, 1739f10f423SAlan Somers in->body.flush.lock_owner); 1749821f1d3SAlan Somers break; 1759821f1d3SAlan Somers case FUSE_FORGET: 1769821f1d3SAlan Somers printf(" nlookup=%lu", in->body.forget.nlookup); 1779821f1d3SAlan Somers break; 1789821f1d3SAlan Somers case FUSE_FSYNC: 1799821f1d3SAlan Somers printf(" flags=%#x", in->body.fsync.fsync_flags); 1809821f1d3SAlan Somers break; 1819821f1d3SAlan Somers case FUSE_FSYNCDIR: 1829821f1d3SAlan Somers printf(" flags=%#x", in->body.fsyncdir.fsync_flags); 1839821f1d3SAlan Somers break; 1849821f1d3SAlan Somers case FUSE_LOOKUP: 1859821f1d3SAlan Somers printf(" %s", in->body.lookup); 1869821f1d3SAlan Somers break; 187bf4d7084SAlan Somers case FUSE_MKNOD: 188bf4d7084SAlan Somers printf(" mode=%#o rdev=%x", in->body.mknod.mode, 189bf4d7084SAlan Somers in->body.mknod.rdev); 190bf4d7084SAlan Somers break; 1919821f1d3SAlan Somers case FUSE_OPEN: 1929821f1d3SAlan Somers printf(" flags=%#x mode=%#o", 1939821f1d3SAlan Somers in->body.open.flags, in->body.open.mode); 1949821f1d3SAlan Somers break; 1959821f1d3SAlan Somers case FUSE_OPENDIR: 1969821f1d3SAlan Somers printf(" flags=%#x mode=%#o", 1979821f1d3SAlan Somers in->body.opendir.flags, in->body.opendir.mode); 1989821f1d3SAlan Somers break; 1999821f1d3SAlan Somers case FUSE_READ: 2009821f1d3SAlan Somers printf(" offset=%lu size=%u", in->body.read.offset, 2019821f1d3SAlan Somers in->body.read.size); 2029821f1d3SAlan Somers break; 2039821f1d3SAlan Somers case FUSE_READDIR: 204363a7416SAlan Somers printf(" fh=%#lx offset=%lu size=%u", 205363a7416SAlan Somers in->body.readdir.fh, in->body.readdir.offset, 2069821f1d3SAlan Somers in->body.readdir.size); 2079821f1d3SAlan Somers break; 2089821f1d3SAlan Somers case FUSE_RELEASE: 20942d50d16SAlan Somers printf(" fh=%#lx flags=%#x lock_owner=%lu", 21042d50d16SAlan Somers in->body.release.fh, 2119821f1d3SAlan Somers in->body.release.flags, 2129821f1d3SAlan Somers in->body.release.lock_owner); 2139821f1d3SAlan Somers break; 2149821f1d3SAlan Somers case FUSE_SETATTR: 2159821f1d3SAlan Somers if (verbosity <= 1) { 2169821f1d3SAlan Somers printf(" valid=%#x", in->body.setattr.valid); 2179821f1d3SAlan Somers break; 2189821f1d3SAlan Somers } 2199821f1d3SAlan Somers if (in->body.setattr.valid & FATTR_MODE) 2209821f1d3SAlan Somers printf(" mode=%#o", in->body.setattr.mode); 2219821f1d3SAlan Somers if (in->body.setattr.valid & FATTR_UID) 2229821f1d3SAlan Somers printf(" uid=%u", in->body.setattr.uid); 2239821f1d3SAlan Somers if (in->body.setattr.valid & FATTR_GID) 2249821f1d3SAlan Somers printf(" gid=%u", in->body.setattr.gid); 2259821f1d3SAlan Somers if (in->body.setattr.valid & FATTR_SIZE) 2269821f1d3SAlan Somers printf(" size=%zu", in->body.setattr.size); 2279821f1d3SAlan Somers if (in->body.setattr.valid & FATTR_ATIME) 2289821f1d3SAlan Somers printf(" atime=%zu.%u", 2299821f1d3SAlan Somers in->body.setattr.atime, 2309821f1d3SAlan Somers in->body.setattr.atimensec); 2319821f1d3SAlan Somers if (in->body.setattr.valid & FATTR_MTIME) 2329821f1d3SAlan Somers printf(" mtime=%zu.%u", 2339821f1d3SAlan Somers in->body.setattr.mtime, 2349821f1d3SAlan Somers in->body.setattr.mtimensec); 2359821f1d3SAlan Somers if (in->body.setattr.valid & FATTR_FH) 2369821f1d3SAlan Somers printf(" fh=%zu", in->body.setattr.fh); 2379821f1d3SAlan Somers break; 2389821f1d3SAlan Somers case FUSE_SETXATTR: 2399821f1d3SAlan Somers /* 2409821f1d3SAlan Somers * In theory neither the xattr name and value need be 2419821f1d3SAlan Somers * ASCII, but in this test suite they always are. 2429821f1d3SAlan Somers */ 24319ef317dSAlan Somers name = (const char*)in->body.bytes + 2449821f1d3SAlan Somers sizeof(fuse_setxattr_in); 24519ef317dSAlan Somers value = name + strlen(name) + 1; 24619ef317dSAlan Somers printf(" %s=%s", name, value); 2479821f1d3SAlan Somers break; 2489821f1d3SAlan Somers case FUSE_WRITE: 24912292a99SAlan Somers printf(" fh=%#lx offset=%lu size=%u flags=%u", 25012292a99SAlan Somers in->body.write.fh, 2519821f1d3SAlan Somers in->body.write.offset, in->body.write.size, 2529821f1d3SAlan Somers in->body.write.write_flags); 2539821f1d3SAlan Somers break; 2549821f1d3SAlan Somers default: 2559821f1d3SAlan Somers break; 2569821f1d3SAlan Somers } 2579821f1d3SAlan Somers printf("\n"); 2589821f1d3SAlan Somers } 2599821f1d3SAlan Somers 26091ff3a0dSAlan Somers MockFS::MockFS(int max_readahead, bool allow_other, bool default_permissions, 261*140bb492SAlan Somers bool push_symlinks_in, bool ro, uint32_t flags) 2629821f1d3SAlan Somers { 2639821f1d3SAlan Somers struct iovec *iov = NULL; 2649821f1d3SAlan Somers int iovlen = 0; 2659821f1d3SAlan Somers char fdstr[15]; 26691ff3a0dSAlan Somers const bool trueval = true; 2679821f1d3SAlan Somers 2689821f1d3SAlan Somers m_daemon_id = NULL; 2699821f1d3SAlan Somers m_maxreadahead = max_readahead; 2709821f1d3SAlan Somers quit = 0; 2719821f1d3SAlan Somers 2729821f1d3SAlan Somers /* 2739821f1d3SAlan Somers * Kyua sets pwd to a testcase-unique tempdir; no need to use 2749821f1d3SAlan Somers * mkdtemp 2759821f1d3SAlan Somers */ 2769821f1d3SAlan Somers /* 2779821f1d3SAlan Somers * googletest doesn't allow ASSERT_ in constructors, so we must throw 2789821f1d3SAlan Somers * instead. 2799821f1d3SAlan Somers */ 28091ff3a0dSAlan Somers if (mkdir("mountpoint" , 0755) && errno != EEXIST) 2819821f1d3SAlan Somers throw(std::system_error(errno, std::system_category(), 2829821f1d3SAlan Somers "Couldn't make mountpoint directory")); 2839821f1d3SAlan Somers 28491ff3a0dSAlan Somers m_fuse_fd = open("/dev/fuse", O_CLOEXEC | O_RDWR); 2859821f1d3SAlan Somers if (m_fuse_fd < 0) 2869821f1d3SAlan Somers throw(std::system_error(errno, std::system_category(), 2879821f1d3SAlan Somers "Couldn't open /dev/fuse")); 2889821f1d3SAlan Somers sprintf(fdstr, "%d", m_fuse_fd); 2899821f1d3SAlan Somers 2909821f1d3SAlan Somers m_pid = getpid(); 29191ff3a0dSAlan Somers m_child_pid = -1; 2929821f1d3SAlan Somers 2939821f1d3SAlan Somers build_iovec(&iov, &iovlen, "fstype", __DECONST(void *, "fusefs"), -1); 2949821f1d3SAlan Somers build_iovec(&iov, &iovlen, "fspath", 2959821f1d3SAlan Somers __DECONST(void *, "mountpoint"), -1); 2969821f1d3SAlan Somers build_iovec(&iov, &iovlen, "from", __DECONST(void *, "/dev/fuse"), -1); 2979821f1d3SAlan Somers build_iovec(&iov, &iovlen, "fd", fdstr, -1); 29891ff3a0dSAlan Somers if (allow_other) { 29991ff3a0dSAlan Somers build_iovec(&iov, &iovlen, "allow_other", 3009821f1d3SAlan Somers __DECONST(void*, &trueval), sizeof(bool)); 3019821f1d3SAlan Somers } 3029821f1d3SAlan Somers if (default_permissions) { 3039821f1d3SAlan Somers build_iovec(&iov, &iovlen, "default_permissions", 3049821f1d3SAlan Somers __DECONST(void*, &trueval), sizeof(bool)); 3059821f1d3SAlan Somers } 30691ff3a0dSAlan Somers if (push_symlinks_in) { 30791ff3a0dSAlan Somers build_iovec(&iov, &iovlen, "push_symlinks_in", 30891ff3a0dSAlan Somers __DECONST(void*, &trueval), sizeof(bool)); 30991ff3a0dSAlan Somers } 310*140bb492SAlan Somers if (ro) { 311*140bb492SAlan Somers build_iovec(&iov, &iovlen, "ro", 312*140bb492SAlan Somers __DECONST(void*, &trueval), sizeof(bool)); 313*140bb492SAlan Somers } 3149821f1d3SAlan Somers if (nmount(iov, iovlen, 0)) 3159821f1d3SAlan Somers throw(std::system_error(errno, std::system_category(), 3169821f1d3SAlan Somers "Couldn't mount filesystem")); 3179821f1d3SAlan Somers 3189821f1d3SAlan Somers // Setup default handler 3199821f1d3SAlan Somers ON_CALL(*this, process(_, _)) 3209821f1d3SAlan Somers .WillByDefault(Invoke(this, &MockFS::process_default)); 3219821f1d3SAlan Somers 3229821f1d3SAlan Somers init(flags); 3239821f1d3SAlan Somers signal(SIGUSR1, sigint_handler); 3249821f1d3SAlan Somers if (pthread_create(&m_daemon_id, NULL, service, (void*)this)) 3259821f1d3SAlan Somers throw(std::system_error(errno, std::system_category(), 3269821f1d3SAlan Somers "Couldn't Couldn't start fuse thread")); 3279821f1d3SAlan Somers } 3289821f1d3SAlan Somers 3299821f1d3SAlan Somers MockFS::~MockFS() { 3309821f1d3SAlan Somers kill_daemon(); 3319821f1d3SAlan Somers ::unmount("mountpoint", MNT_FORCE); 3329821f1d3SAlan Somers if (m_daemon_id != NULL) { 3339821f1d3SAlan Somers pthread_join(m_daemon_id, NULL); 3349821f1d3SAlan Somers m_daemon_id = NULL; 3359821f1d3SAlan Somers } 3369821f1d3SAlan Somers rmdir("mountpoint"); 3379821f1d3SAlan Somers } 3389821f1d3SAlan Somers 3399821f1d3SAlan Somers void MockFS::init(uint32_t flags) { 3409821f1d3SAlan Somers mockfs_buf_in *in; 3419821f1d3SAlan Somers mockfs_buf_out *out; 3429821f1d3SAlan Somers 3439821f1d3SAlan Somers in = (mockfs_buf_in*) malloc(sizeof(*in)); 3449821f1d3SAlan Somers ASSERT_TRUE(in != NULL); 3459821f1d3SAlan Somers out = (mockfs_buf_out*) malloc(sizeof(*out)); 3469821f1d3SAlan Somers ASSERT_TRUE(out != NULL); 3479821f1d3SAlan Somers 3489821f1d3SAlan Somers read_request(in); 3499821f1d3SAlan Somers ASSERT_EQ(FUSE_INIT, in->header.opcode); 3509821f1d3SAlan Somers 3519821f1d3SAlan Somers memset(out, 0, sizeof(*out)); 3529821f1d3SAlan Somers out->header.unique = in->header.unique; 3539821f1d3SAlan Somers out->header.error = 0; 3549821f1d3SAlan Somers out->body.init.major = FUSE_KERNEL_VERSION; 3559821f1d3SAlan Somers out->body.init.minor = FUSE_KERNEL_MINOR_VERSION; 3569821f1d3SAlan Somers out->body.init.flags = in->body.init.flags & flags; 3579821f1d3SAlan Somers 3589821f1d3SAlan Somers /* 3599821f1d3SAlan Somers * The default max_write is set to this formula in libfuse, though 3609821f1d3SAlan Somers * individual filesystems can lower it. The "- 4096" was added in 3619821f1d3SAlan Somers * commit 154ffe2, with the commit message "fix". 3629821f1d3SAlan Somers */ 3639821f1d3SAlan Somers uint32_t default_max_write = 32 * getpagesize() + 0x1000 - 4096; 3649821f1d3SAlan Somers /* For testing purposes, it should be distinct from MAXPHYS */ 3659821f1d3SAlan Somers m_max_write = MIN(default_max_write, MAXPHYS / 2); 3669821f1d3SAlan Somers out->body.init.max_write = m_max_write; 3679821f1d3SAlan Somers 3689821f1d3SAlan Somers out->body.init.max_readahead = m_maxreadahead; 3699821f1d3SAlan Somers SET_OUT_HEADER_LEN(out, init); 3709821f1d3SAlan Somers write(m_fuse_fd, out, out->header.len); 3719821f1d3SAlan Somers 3729821f1d3SAlan Somers free(in); 3739821f1d3SAlan Somers } 3749821f1d3SAlan Somers 3759821f1d3SAlan Somers void MockFS::kill_daemon() { 3769821f1d3SAlan Somers if (m_daemon_id != NULL) { 3779821f1d3SAlan Somers pthread_kill(m_daemon_id, SIGUSR1); 3789821f1d3SAlan Somers // Closing the /dev/fuse file descriptor first allows unmount 3799821f1d3SAlan Somers // to succeed even if the daemon doesn't correctly respond to 3809821f1d3SAlan Somers // commands during the unmount sequence. 3819821f1d3SAlan Somers close(m_fuse_fd); 3829821f1d3SAlan Somers } 3839821f1d3SAlan Somers } 3849821f1d3SAlan Somers 3859821f1d3SAlan Somers void MockFS::loop() { 3869821f1d3SAlan Somers mockfs_buf_in *in; 3879821f1d3SAlan Somers std::vector<mockfs_buf_out*> out; 3889821f1d3SAlan Somers 3899821f1d3SAlan Somers in = (mockfs_buf_in*) malloc(sizeof(*in)); 3909821f1d3SAlan Somers ASSERT_TRUE(in != NULL); 3919821f1d3SAlan Somers while (!quit) { 3929821f1d3SAlan Somers bzero(in, sizeof(*in)); 3939821f1d3SAlan Somers read_request(in); 3949821f1d3SAlan Somers if (quit) 3959821f1d3SAlan Somers break; 3969821f1d3SAlan Somers if (verbosity > 0) 3979821f1d3SAlan Somers debug_fuseop(in); 3989821f1d3SAlan Somers if (pid_ok((pid_t)in->header.pid)) { 3999821f1d3SAlan Somers process(in, out); 4009821f1d3SAlan Somers } else { 4019821f1d3SAlan Somers /* 4029821f1d3SAlan Somers * Reject any requests from unknown processes. Because 4039821f1d3SAlan Somers * we actually do mount a filesystem, plenty of 4049821f1d3SAlan Somers * unrelated system daemons may try to access it. 4059821f1d3SAlan Somers */ 4069821f1d3SAlan Somers process_default(in, out); 4079821f1d3SAlan Somers } 4089821f1d3SAlan Somers for (auto &it: out) { 4099821f1d3SAlan Somers ASSERT_TRUE(write(m_fuse_fd, it, it->header.len) > 0 || 4109821f1d3SAlan Somers errno == EAGAIN) 4119821f1d3SAlan Somers << strerror(errno); 4129821f1d3SAlan Somers delete it; 4139821f1d3SAlan Somers } 4149821f1d3SAlan Somers out.clear(); 4159821f1d3SAlan Somers } 4169821f1d3SAlan Somers free(in); 4179821f1d3SAlan Somers } 4189821f1d3SAlan Somers 4199821f1d3SAlan Somers bool MockFS::pid_ok(pid_t pid) { 4209821f1d3SAlan Somers if (pid == m_pid) { 4219821f1d3SAlan Somers return (true); 42291ff3a0dSAlan Somers } else if (pid == m_child_pid) { 42391ff3a0dSAlan Somers return (true); 4249821f1d3SAlan Somers } else { 4259821f1d3SAlan Somers struct kinfo_proc *ki; 4269821f1d3SAlan Somers bool ok = false; 4279821f1d3SAlan Somers 4289821f1d3SAlan Somers ki = kinfo_getproc(pid); 4299821f1d3SAlan Somers if (ki == NULL) 4309821f1d3SAlan Somers return (false); 4319821f1d3SAlan Somers /* 4329821f1d3SAlan Somers * Allow access by the aio daemon processes so that our tests 4339821f1d3SAlan Somers * can use aio functions 4349821f1d3SAlan Somers */ 4359821f1d3SAlan Somers if (0 == strncmp("aiod", ki->ki_comm, 4)) 4369821f1d3SAlan Somers ok = true; 4379821f1d3SAlan Somers free(ki); 4389821f1d3SAlan Somers return (ok); 4399821f1d3SAlan Somers } 4409821f1d3SAlan Somers } 4419821f1d3SAlan Somers 4429821f1d3SAlan Somers void MockFS::process_default(const mockfs_buf_in *in, 4439821f1d3SAlan Somers std::vector<mockfs_buf_out*> &out) 4449821f1d3SAlan Somers { 4459821f1d3SAlan Somers auto out0 = new mockfs_buf_out; 4469821f1d3SAlan Somers out0->header.unique = in->header.unique; 4479821f1d3SAlan Somers out0->header.error = -EOPNOTSUPP; 4489821f1d3SAlan Somers out0->header.len = sizeof(out0->header); 4499821f1d3SAlan Somers out.push_back(out0); 4509821f1d3SAlan Somers } 4519821f1d3SAlan Somers 4529821f1d3SAlan Somers void MockFS::read_request(mockfs_buf_in *in) { 4539821f1d3SAlan Somers ssize_t res; 4549821f1d3SAlan Somers 4559821f1d3SAlan Somers res = read(m_fuse_fd, in, sizeof(*in)); 4569821f1d3SAlan Somers if (res < 0 && !quit) 4579821f1d3SAlan Somers perror("read"); 4589821f1d3SAlan Somers ASSERT_TRUE(res >= (ssize_t)sizeof(in->header) || quit); 4599821f1d3SAlan Somers } 4609821f1d3SAlan Somers 4619821f1d3SAlan Somers void* MockFS::service(void *pthr_data) { 4629821f1d3SAlan Somers MockFS *mock_fs = (MockFS*)pthr_data; 4639821f1d3SAlan Somers 4649821f1d3SAlan Somers mock_fs->loop(); 4659821f1d3SAlan Somers 4669821f1d3SAlan Somers return (NULL); 4679821f1d3SAlan Somers } 4689821f1d3SAlan Somers 4699821f1d3SAlan Somers void MockFS::unmount() { 4709821f1d3SAlan Somers ::unmount("mountpoint", 0); 4719821f1d3SAlan Somers } 472