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 { 6537df9d3bSAlan Somers const char* table[] = { 669821f1d3SAlan Somers "Unknown (opcode 0)", 679821f1d3SAlan Somers "LOOKUP", 689821f1d3SAlan Somers "FORGET", 699821f1d3SAlan Somers "GETATTR", 709821f1d3SAlan Somers "SETATTR", 719821f1d3SAlan Somers "READLINK", 729821f1d3SAlan Somers "SYMLINK", 739821f1d3SAlan Somers "Unknown (opcode 7)", 749821f1d3SAlan Somers "MKNOD", 759821f1d3SAlan Somers "MKDIR", 769821f1d3SAlan Somers "UNLINK", 779821f1d3SAlan Somers "RMDIR", 789821f1d3SAlan Somers "RENAME", 799821f1d3SAlan Somers "LINK", 809821f1d3SAlan Somers "OPEN", 819821f1d3SAlan Somers "READ", 829821f1d3SAlan Somers "WRITE", 839821f1d3SAlan Somers "STATFS", 849821f1d3SAlan Somers "RELEASE", 859821f1d3SAlan Somers "Unknown (opcode 19)", 869821f1d3SAlan Somers "FSYNC", 879821f1d3SAlan Somers "SETXATTR", 889821f1d3SAlan Somers "GETXATTR", 899821f1d3SAlan Somers "LISTXATTR", 909821f1d3SAlan Somers "REMOVEXATTR", 919821f1d3SAlan Somers "FLUSH", 929821f1d3SAlan Somers "INIT", 939821f1d3SAlan Somers "OPENDIR", 949821f1d3SAlan Somers "READDIR", 959821f1d3SAlan Somers "RELEASEDIR", 969821f1d3SAlan Somers "FSYNCDIR", 979821f1d3SAlan Somers "GETLK", 989821f1d3SAlan Somers "SETLK", 999821f1d3SAlan Somers "SETLKW", 1009821f1d3SAlan Somers "ACCESS", 1019821f1d3SAlan Somers "CREATE", 1029821f1d3SAlan Somers "INTERRUPT", 1039821f1d3SAlan Somers "BMAP", 10437df9d3bSAlan Somers "DESTROY", 10537df9d3bSAlan Somers "IOCTL", 10637df9d3bSAlan Somers "POLL", 10737df9d3bSAlan Somers "NOTIFY_REPLY", 10837df9d3bSAlan Somers "BATCH_FORGET", 10937df9d3bSAlan Somers "FALLOCATE", 11037df9d3bSAlan Somers "READDIRPLUS", 11137df9d3bSAlan Somers "RENAME2", 11237df9d3bSAlan Somers "LSEEK", 11392bbfe1fSAlan Somers "COPY_FILE_RANGE", 1149821f1d3SAlan Somers }; 11537df9d3bSAlan Somers if (opcode >= nitems(table)) 1169821f1d3SAlan Somers return ("Unknown (opcode > max)"); 1179821f1d3SAlan Somers else 1189821f1d3SAlan Somers return (table[opcode]); 1199821f1d3SAlan Somers } 1209821f1d3SAlan Somers 1219821f1d3SAlan Somers ProcessMockerT 1229821f1d3SAlan Somers ReturnErrno(int error) 1239821f1d3SAlan Somers { 1249821f1d3SAlan Somers return([=](auto in, auto &out) { 12529edc611SAlan Somers std::unique_ptr<mockfs_buf_out> out0(new mockfs_buf_out); 12629edc611SAlan Somers out0->header.unique = in.header.unique; 1279821f1d3SAlan Somers out0->header.error = -error; 1289821f1d3SAlan Somers out0->header.len = sizeof(out0->header); 12929edc611SAlan Somers out.push_back(std::move(out0)); 1309821f1d3SAlan Somers }); 1319821f1d3SAlan Somers } 1329821f1d3SAlan Somers 1339821f1d3SAlan Somers /* Helper function used for returning negative cache entries for LOOKUP */ 1349821f1d3SAlan Somers ProcessMockerT 1359821f1d3SAlan Somers ReturnNegativeCache(const struct timespec *entry_valid) 1369821f1d3SAlan Somers { 1379821f1d3SAlan Somers return([=](auto in, auto &out) { 1389821f1d3SAlan Somers /* nodeid means ENOENT and cache it */ 13929edc611SAlan Somers std::unique_ptr<mockfs_buf_out> out0(new mockfs_buf_out); 1409821f1d3SAlan Somers out0->body.entry.nodeid = 0; 14129edc611SAlan Somers out0->header.unique = in.header.unique; 1429821f1d3SAlan Somers out0->header.error = 0; 1439821f1d3SAlan Somers out0->body.entry.entry_valid = entry_valid->tv_sec; 1449821f1d3SAlan Somers out0->body.entry.entry_valid_nsec = entry_valid->tv_nsec; 14529edc611SAlan Somers SET_OUT_HEADER_LEN(*out0, entry); 14629edc611SAlan Somers out.push_back(std::move(out0)); 1479821f1d3SAlan Somers }); 1489821f1d3SAlan Somers } 1499821f1d3SAlan Somers 1509821f1d3SAlan Somers ProcessMockerT 15129edc611SAlan Somers ReturnImmediate(std::function<void(const mockfs_buf_in& in, 15229edc611SAlan Somers struct mockfs_buf_out &out)> f) 1539821f1d3SAlan Somers { 15429edc611SAlan Somers return([=](auto& in, auto &out) { 15529edc611SAlan Somers std::unique_ptr<mockfs_buf_out> out0(new mockfs_buf_out); 15629edc611SAlan Somers out0->header.unique = in.header.unique; 15729edc611SAlan Somers f(in, *out0); 15829edc611SAlan Somers out.push_back(std::move(out0)); 1599821f1d3SAlan Somers }); 1609821f1d3SAlan Somers } 1619821f1d3SAlan Somers 1629821f1d3SAlan Somers void sigint_handler(int __unused sig) { 1638b73a4c5SAlan Somers // Don't do anything except interrupt the daemon's read(2) call 1649821f1d3SAlan Somers } 1659821f1d3SAlan Somers 1666c0c3620SAlan Somers void MockFS::debug_request(const mockfs_buf_in &in, ssize_t buflen) 1679821f1d3SAlan Somers { 16829edc611SAlan Somers printf("%-11s ino=%2" PRIu64, opcode2opname(in.header.opcode), 16929edc611SAlan Somers in.header.nodeid); 1709821f1d3SAlan Somers if (verbosity > 1) { 1716c0c3620SAlan Somers printf(" uid=%5u gid=%5u pid=%5u unique=%" PRIu64 " len=%u" 1726c0c3620SAlan Somers " buflen=%zd", 17329edc611SAlan Somers in.header.uid, in.header.gid, in.header.pid, 1746c0c3620SAlan Somers in.header.unique, in.header.len, buflen); 1759821f1d3SAlan Somers } 17629edc611SAlan Somers switch (in.header.opcode) { 17719ef317dSAlan Somers const char *name, *value; 17819ef317dSAlan Somers 179caf5f57dSAlan Somers case FUSE_ACCESS: 18029edc611SAlan Somers printf(" mask=%#x", in.body.access.mask); 181caf5f57dSAlan Somers break; 182a1c9f4adSAlan Somers case FUSE_BMAP: 18397b0512bSAlan Somers printf(" block=%" PRIx64 " blocksize=%#x", 18497b0512bSAlan Somers in.body.bmap.block, in.body.bmap.blocksize); 185a1c9f4adSAlan Somers break; 18692bbfe1fSAlan Somers case FUSE_COPY_FILE_RANGE: 18792bbfe1fSAlan Somers printf(" off_in=%" PRIu64 " ino_out=%" PRIu64 18892bbfe1fSAlan Somers " off_out=%" PRIu64 " size=%" PRIu64, 18992bbfe1fSAlan Somers in.body.copy_file_range.off_in, 19092bbfe1fSAlan Somers in.body.copy_file_range.nodeid_out, 19192bbfe1fSAlan Somers in.body.copy_file_range.off_out, 19292bbfe1fSAlan Somers in.body.copy_file_range.len); 19392bbfe1fSAlan Somers if (verbosity > 1) 19492bbfe1fSAlan Somers printf(" fh_in=%" PRIu64 " fh_out=%" PRIu64 19592bbfe1fSAlan Somers " flags=%" PRIx64, 19692bbfe1fSAlan Somers in.body.copy_file_range.fh_in, 19792bbfe1fSAlan Somers in.body.copy_file_range.fh_out, 19892bbfe1fSAlan Somers in.body.copy_file_range.flags); 19992bbfe1fSAlan Somers break; 20019ef317dSAlan Somers case FUSE_CREATE: 201a4856c96SAlan Somers if (m_kernel_minor_version >= 12) 202a4856c96SAlan Somers name = (const char*)in.body.bytes + 203a4856c96SAlan Somers sizeof(fuse_create_in); 204a4856c96SAlan Somers else 20529edc611SAlan Somers name = (const char*)in.body.bytes + 20619ef317dSAlan Somers sizeof(fuse_open_in); 20719ef317dSAlan Somers printf(" flags=%#x name=%s", 20829edc611SAlan Somers in.body.open.flags, name); 20919ef317dSAlan Somers break; 2109821f1d3SAlan Somers case FUSE_FLUSH: 211cc04566cSAlan Somers printf(" fh=%#" PRIx64 " lock_owner=%" PRIu64, 21229edc611SAlan Somers in.body.flush.fh, 21329edc611SAlan Somers in.body.flush.lock_owner); 2149821f1d3SAlan Somers break; 2159821f1d3SAlan Somers case FUSE_FORGET: 21629edc611SAlan Somers printf(" nlookup=%" PRIu64, in.body.forget.nlookup); 2179821f1d3SAlan Somers break; 2189821f1d3SAlan Somers case FUSE_FSYNC: 21929edc611SAlan Somers printf(" flags=%#x", in.body.fsync.fsync_flags); 2209821f1d3SAlan Somers break; 2219821f1d3SAlan Somers case FUSE_FSYNCDIR: 22229edc611SAlan Somers printf(" flags=%#x", in.body.fsyncdir.fsync_flags); 2239821f1d3SAlan Somers break; 224723c7768SAlan Somers case FUSE_INTERRUPT: 22529edc611SAlan Somers printf(" unique=%" PRIu64, in.body.interrupt.unique); 226723c7768SAlan Somers break; 227002e54b0SAlan Somers case FUSE_LINK: 22829edc611SAlan Somers printf(" oldnodeid=%" PRIu64, in.body.link.oldnodeid); 229002e54b0SAlan Somers break; 2305e633330SAlan Somers case FUSE_LISTXATTR: 2315e633330SAlan Somers printf(" size=%" PRIu32, in.body.listxattr.size); 2325e633330SAlan Somers break; 2339821f1d3SAlan Somers case FUSE_LOOKUP: 23429edc611SAlan Somers printf(" %s", in.body.lookup); 2359821f1d3SAlan Somers break; 23637df9d3bSAlan Somers case FUSE_LSEEK: 23737df9d3bSAlan Somers switch (in.body.lseek.whence) { 23837df9d3bSAlan Somers case SEEK_HOLE: 2391d010cd3SCy Schubert printf(" SEEK_HOLE offset=%jd", 24037df9d3bSAlan Somers in.body.lseek.offset); 24137df9d3bSAlan Somers break; 24237df9d3bSAlan Somers case SEEK_DATA: 2431d010cd3SCy Schubert printf(" SEEK_DATA offset=%jd", 24437df9d3bSAlan Somers in.body.lseek.offset); 24537df9d3bSAlan Somers break; 24637df9d3bSAlan Somers default: 2471d010cd3SCy Schubert printf(" whence=%u offset=%jd", 24837df9d3bSAlan Somers in.body.lseek.whence, in.body.lseek.offset); 24937df9d3bSAlan Somers break; 25037df9d3bSAlan Somers } 25137df9d3bSAlan Somers break; 25299cf7bffSAlan Somers case FUSE_MKDIR: 25329edc611SAlan Somers name = (const char*)in.body.bytes + 25499cf7bffSAlan Somers sizeof(fuse_mkdir_in); 255a4856c96SAlan Somers printf(" name=%s mode=%#o umask=%#o", name, 256a4856c96SAlan Somers in.body.mkdir.mode, in.body.mkdir.umask); 25799cf7bffSAlan Somers break; 258bf4d7084SAlan Somers case FUSE_MKNOD: 259a4856c96SAlan Somers if (m_kernel_minor_version >= 12) 260a4856c96SAlan Somers name = (const char*)in.body.bytes + 261a4856c96SAlan Somers sizeof(fuse_mknod_in); 262a4856c96SAlan Somers else 263a4856c96SAlan Somers name = (const char*)in.body.bytes + 264a4856c96SAlan Somers FUSE_COMPAT_MKNOD_IN_SIZE; 265a4856c96SAlan Somers printf(" mode=%#o rdev=%x umask=%#o name=%s", 266a4856c96SAlan Somers in.body.mknod.mode, in.body.mknod.rdev, 267a4856c96SAlan Somers in.body.mknod.umask, name); 268bf4d7084SAlan Somers break; 2699821f1d3SAlan Somers case FUSE_OPEN: 270a4856c96SAlan Somers printf(" flags=%#x", in.body.open.flags); 2719821f1d3SAlan Somers break; 2729821f1d3SAlan Somers case FUSE_OPENDIR: 273a4856c96SAlan Somers printf(" flags=%#x", in.body.opendir.flags); 2749821f1d3SAlan Somers break; 2759821f1d3SAlan Somers case FUSE_READ: 276cc04566cSAlan Somers printf(" offset=%" PRIu64 " size=%u", 27729edc611SAlan Somers in.body.read.offset, 27829edc611SAlan Somers in.body.read.size); 279d4fd0c81SAlan Somers if (verbosity > 1) 280d4fd0c81SAlan Somers printf(" flags=%#x", in.body.read.flags); 2819821f1d3SAlan Somers break; 2829821f1d3SAlan Somers case FUSE_READDIR: 283cc04566cSAlan Somers printf(" fh=%#" PRIx64 " offset=%" PRIu64 " size=%u", 28429edc611SAlan Somers in.body.readdir.fh, in.body.readdir.offset, 28529edc611SAlan Somers in.body.readdir.size); 2869821f1d3SAlan Somers break; 2879821f1d3SAlan Somers case FUSE_RELEASE: 288cc04566cSAlan Somers printf(" fh=%#" PRIx64 " flags=%#x lock_owner=%" PRIu64, 28929edc611SAlan Somers in.body.release.fh, 29029edc611SAlan Somers in.body.release.flags, 29129edc611SAlan Somers in.body.release.lock_owner); 2929821f1d3SAlan Somers break; 2939821f1d3SAlan Somers case FUSE_SETATTR: 2949821f1d3SAlan Somers if (verbosity <= 1) { 29529edc611SAlan Somers printf(" valid=%#x", in.body.setattr.valid); 2969821f1d3SAlan Somers break; 2979821f1d3SAlan Somers } 29829edc611SAlan Somers if (in.body.setattr.valid & FATTR_MODE) 29929edc611SAlan Somers printf(" mode=%#o", in.body.setattr.mode); 30029edc611SAlan Somers if (in.body.setattr.valid & FATTR_UID) 30129edc611SAlan Somers printf(" uid=%u", in.body.setattr.uid); 30229edc611SAlan Somers if (in.body.setattr.valid & FATTR_GID) 30329edc611SAlan Somers printf(" gid=%u", in.body.setattr.gid); 30429edc611SAlan Somers if (in.body.setattr.valid & FATTR_SIZE) 30529edc611SAlan Somers printf(" size=%" PRIu64, in.body.setattr.size); 30629edc611SAlan Somers if (in.body.setattr.valid & FATTR_ATIME) 307cc04566cSAlan Somers printf(" atime=%" PRIu64 ".%u", 30829edc611SAlan Somers in.body.setattr.atime, 30929edc611SAlan Somers in.body.setattr.atimensec); 31029edc611SAlan Somers if (in.body.setattr.valid & FATTR_MTIME) 311cc04566cSAlan Somers printf(" mtime=%" PRIu64 ".%u", 31229edc611SAlan Somers in.body.setattr.mtime, 31329edc611SAlan Somers in.body.setattr.mtimensec); 31429edc611SAlan Somers if (in.body.setattr.valid & FATTR_FH) 31529edc611SAlan Somers printf(" fh=%" PRIu64 "", in.body.setattr.fh); 3169821f1d3SAlan Somers break; 317f067b609SAlan Somers case FUSE_SETLK: 318cc04566cSAlan Somers printf(" fh=%#" PRIx64 " owner=%" PRIu64 319cc04566cSAlan Somers " type=%u pid=%u", 32029edc611SAlan Somers in.body.setlk.fh, in.body.setlk.owner, 32129edc611SAlan Somers in.body.setlk.lk.type, 32229edc611SAlan Somers in.body.setlk.lk.pid); 323f067b609SAlan Somers if (verbosity >= 2) { 324cc04566cSAlan Somers printf(" range=[%" PRIu64 "-%" PRIu64 "]", 32529edc611SAlan Somers in.body.setlk.lk.start, 32629edc611SAlan Somers in.body.setlk.lk.end); 327f067b609SAlan Somers } 328f067b609SAlan Somers break; 3299821f1d3SAlan Somers case FUSE_SETXATTR: 3309821f1d3SAlan Somers /* 3319821f1d3SAlan Somers * In theory neither the xattr name and value need be 3329821f1d3SAlan Somers * ASCII, but in this test suite they always are. 3339821f1d3SAlan Somers */ 33429edc611SAlan Somers name = (const char*)in.body.bytes + 3359821f1d3SAlan Somers sizeof(fuse_setxattr_in); 33619ef317dSAlan Somers value = name + strlen(name) + 1; 33719ef317dSAlan Somers printf(" %s=%s", name, value); 3389821f1d3SAlan Somers break; 3399821f1d3SAlan Somers case FUSE_WRITE: 340cc04566cSAlan Somers printf(" fh=%#" PRIx64 " offset=%" PRIu64 341d4fd0c81SAlan Somers " size=%u write_flags=%u", 34229edc611SAlan Somers in.body.write.fh, 34329edc611SAlan Somers in.body.write.offset, in.body.write.size, 34429edc611SAlan Somers in.body.write.write_flags); 345d4fd0c81SAlan Somers if (verbosity > 1) 346d4fd0c81SAlan Somers printf(" flags=%#x", in.body.write.flags); 3479821f1d3SAlan Somers break; 3489821f1d3SAlan Somers default: 3499821f1d3SAlan Somers break; 3509821f1d3SAlan Somers } 3519821f1d3SAlan Somers printf("\n"); 3529821f1d3SAlan Somers } 3539821f1d3SAlan Somers 354c2d70d6eSAlan Somers /* 355c2d70d6eSAlan Somers * Debug a FUSE response. 356c2d70d6eSAlan Somers * 357c2d70d6eSAlan Somers * This is mostly useful for asynchronous notifications, which don't correspond 358c2d70d6eSAlan Somers * to any request 359c2d70d6eSAlan Somers */ 360c2d70d6eSAlan Somers void MockFS::debug_response(const mockfs_buf_out &out) { 361c2d70d6eSAlan Somers const char *name; 362c2d70d6eSAlan Somers 363c2d70d6eSAlan Somers if (verbosity == 0) 364c2d70d6eSAlan Somers return; 365c2d70d6eSAlan Somers 366c2d70d6eSAlan Somers switch (out.header.error) { 367c2d70d6eSAlan Somers case FUSE_NOTIFY_INVAL_ENTRY: 368c2d70d6eSAlan Somers name = (const char*)out.body.bytes + 369c2d70d6eSAlan Somers sizeof(fuse_notify_inval_entry_out); 370c2d70d6eSAlan Somers printf("<- INVAL_ENTRY parent=%" PRIu64 " %s\n", 371c2d70d6eSAlan Somers out.body.inval_entry.parent, name); 372c2d70d6eSAlan Somers break; 373eae1ae13SAlan Somers case FUSE_NOTIFY_INVAL_INODE: 374eae1ae13SAlan Somers printf("<- INVAL_INODE ino=%" PRIu64 " off=%" PRIi64 375eae1ae13SAlan Somers " len=%" PRIi64 "\n", 376eae1ae13SAlan Somers out.body.inval_inode.ino, 377eae1ae13SAlan Somers out.body.inval_inode.off, 378eae1ae13SAlan Somers out.body.inval_inode.len); 379eae1ae13SAlan Somers break; 3807cbb8e8aSAlan Somers case FUSE_NOTIFY_STORE: 3817cbb8e8aSAlan Somers printf("<- STORE ino=%" PRIu64 " off=%" PRIu64 3827cbb8e8aSAlan Somers " size=%" PRIu32 "\n", 3837cbb8e8aSAlan Somers out.body.store.nodeid, 3847cbb8e8aSAlan Somers out.body.store.offset, 3857cbb8e8aSAlan Somers out.body.store.size); 3867cbb8e8aSAlan Somers break; 387c2d70d6eSAlan Somers default: 388c2d70d6eSAlan Somers break; 389c2d70d6eSAlan Somers } 390c2d70d6eSAlan Somers } 391c2d70d6eSAlan Somers 39291ff3a0dSAlan Somers MockFS::MockFS(int max_readahead, bool allow_other, bool default_permissions, 39316bd2d47SAlan Somers bool push_symlinks_in, bool ro, enum poll_method pm, uint32_t flags, 394402b609cSAlan Somers uint32_t kernel_minor_version, uint32_t max_write, bool async, 395ed74f781SAlan Somers bool noclusterr, unsigned time_gran, bool nointr) 3969821f1d3SAlan Somers { 3978b73a4c5SAlan Somers struct sigaction sa; 3989821f1d3SAlan Somers struct iovec *iov = NULL; 3999821f1d3SAlan Somers int iovlen = 0; 4009821f1d3SAlan Somers char fdstr[15]; 40191ff3a0dSAlan Somers const bool trueval = true; 4029821f1d3SAlan Somers 4039821f1d3SAlan Somers m_daemon_id = NULL; 40416bd2d47SAlan Somers m_kernel_minor_version = kernel_minor_version; 4059821f1d3SAlan Somers m_maxreadahead = max_readahead; 406f928dbcbSAlan Somers m_maxwrite = MIN(max_write, max_max_write); 4070a7c63e0SAlan Somers m_nready = -1; 4083429092cSAlan Somers m_pm = pm; 409fef46454SAlan Somers m_time_gran = time_gran; 41081a619c4SAlan Somers m_quit = false; 4113429092cSAlan Somers if (m_pm == KQ) 4123429092cSAlan Somers m_kq = kqueue(); 4133429092cSAlan Somers else 4143429092cSAlan Somers m_kq = -1; 4159821f1d3SAlan Somers 4169821f1d3SAlan Somers /* 4179821f1d3SAlan Somers * Kyua sets pwd to a testcase-unique tempdir; no need to use 4189821f1d3SAlan Somers * mkdtemp 4199821f1d3SAlan Somers */ 4209821f1d3SAlan Somers /* 4219821f1d3SAlan Somers * googletest doesn't allow ASSERT_ in constructors, so we must throw 4229821f1d3SAlan Somers * instead. 4239821f1d3SAlan Somers */ 42491ff3a0dSAlan Somers if (mkdir("mountpoint" , 0755) && errno != EEXIST) 4259821f1d3SAlan Somers throw(std::system_error(errno, std::system_category(), 4269821f1d3SAlan Somers "Couldn't make mountpoint directory")); 4279821f1d3SAlan Somers 4283429092cSAlan Somers switch (m_pm) { 4293429092cSAlan Somers case BLOCKING: 43091ff3a0dSAlan Somers m_fuse_fd = open("/dev/fuse", O_CLOEXEC | O_RDWR); 4313429092cSAlan Somers break; 4323429092cSAlan Somers default: 4333429092cSAlan Somers m_fuse_fd = open("/dev/fuse", O_CLOEXEC | O_RDWR | O_NONBLOCK); 4343429092cSAlan Somers break; 4353429092cSAlan Somers } 4369821f1d3SAlan Somers if (m_fuse_fd < 0) 4379821f1d3SAlan Somers throw(std::system_error(errno, std::system_category(), 4389821f1d3SAlan Somers "Couldn't open /dev/fuse")); 4399821f1d3SAlan Somers 4409821f1d3SAlan Somers m_pid = getpid(); 44191ff3a0dSAlan Somers m_child_pid = -1; 4429821f1d3SAlan Somers 4439821f1d3SAlan Somers build_iovec(&iov, &iovlen, "fstype", __DECONST(void *, "fusefs"), -1); 4449821f1d3SAlan Somers build_iovec(&iov, &iovlen, "fspath", 4459821f1d3SAlan Somers __DECONST(void *, "mountpoint"), -1); 4469821f1d3SAlan Somers build_iovec(&iov, &iovlen, "from", __DECONST(void *, "/dev/fuse"), -1); 4473429092cSAlan Somers sprintf(fdstr, "%d", m_fuse_fd); 4489821f1d3SAlan Somers build_iovec(&iov, &iovlen, "fd", fdstr, -1); 44991ff3a0dSAlan Somers if (allow_other) { 45091ff3a0dSAlan Somers build_iovec(&iov, &iovlen, "allow_other", 4519821f1d3SAlan Somers __DECONST(void*, &trueval), sizeof(bool)); 4529821f1d3SAlan Somers } 4539821f1d3SAlan Somers if (default_permissions) { 4549821f1d3SAlan Somers build_iovec(&iov, &iovlen, "default_permissions", 4559821f1d3SAlan Somers __DECONST(void*, &trueval), sizeof(bool)); 4569821f1d3SAlan Somers } 45791ff3a0dSAlan Somers if (push_symlinks_in) { 45891ff3a0dSAlan Somers build_iovec(&iov, &iovlen, "push_symlinks_in", 45991ff3a0dSAlan Somers __DECONST(void*, &trueval), sizeof(bool)); 46091ff3a0dSAlan Somers } 461140bb492SAlan Somers if (ro) { 462140bb492SAlan Somers build_iovec(&iov, &iovlen, "ro", 463140bb492SAlan Somers __DECONST(void*, &trueval), sizeof(bool)); 464140bb492SAlan Somers } 4658eecd9ceSAlan Somers if (async) { 4668eecd9ceSAlan Somers build_iovec(&iov, &iovlen, "async", __DECONST(void*, &trueval), 4678eecd9ceSAlan Somers sizeof(bool)); 4688eecd9ceSAlan Somers } 469402b609cSAlan Somers if (noclusterr) { 470402b609cSAlan Somers build_iovec(&iov, &iovlen, "noclusterr", 471402b609cSAlan Somers __DECONST(void*, &trueval), sizeof(bool)); 472402b609cSAlan Somers } 473ed74f781SAlan Somers if (nointr) { 474ed74f781SAlan Somers build_iovec(&iov, &iovlen, "nointr", 475ed74f781SAlan Somers __DECONST(void*, &trueval), sizeof(bool)); 476ed74f781SAlan Somers } else { 477ed74f781SAlan Somers build_iovec(&iov, &iovlen, "intr", 478ed74f781SAlan Somers __DECONST(void*, &trueval), sizeof(bool)); 479ed74f781SAlan Somers } 4809821f1d3SAlan Somers if (nmount(iov, iovlen, 0)) 4819821f1d3SAlan Somers throw(std::system_error(errno, std::system_category(), 4829821f1d3SAlan Somers "Couldn't mount filesystem")); 4839821f1d3SAlan Somers 4849821f1d3SAlan Somers // Setup default handler 4859821f1d3SAlan Somers ON_CALL(*this, process(_, _)) 4869821f1d3SAlan Somers .WillByDefault(Invoke(this, &MockFS::process_default)); 4879821f1d3SAlan Somers 4889821f1d3SAlan Somers init(flags); 4898b73a4c5SAlan Somers bzero(&sa, sizeof(sa)); 4908b73a4c5SAlan Somers sa.sa_handler = sigint_handler; 4918b73a4c5SAlan Somers sa.sa_flags = 0; /* Don't set SA_RESTART! */ 4928b73a4c5SAlan Somers if (0 != sigaction(SIGUSR1, &sa, NULL)) 4938b73a4c5SAlan Somers throw(std::system_error(errno, std::system_category(), 4948b73a4c5SAlan Somers "Couldn't handle SIGUSR1")); 4959821f1d3SAlan Somers if (pthread_create(&m_daemon_id, NULL, service, (void*)this)) 4969821f1d3SAlan Somers throw(std::system_error(errno, std::system_category(), 4979821f1d3SAlan Somers "Couldn't Couldn't start fuse thread")); 4989821f1d3SAlan Somers } 4999821f1d3SAlan Somers 5009821f1d3SAlan Somers MockFS::~MockFS() { 5019821f1d3SAlan Somers kill_daemon(); 5029821f1d3SAlan Somers if (m_daemon_id != NULL) { 5039821f1d3SAlan Somers pthread_join(m_daemon_id, NULL); 5049821f1d3SAlan Somers m_daemon_id = NULL; 5059821f1d3SAlan Somers } 5068b73a4c5SAlan Somers ::unmount("mountpoint", MNT_FORCE); 5079821f1d3SAlan Somers rmdir("mountpoint"); 5083429092cSAlan Somers if (m_kq >= 0) 5093429092cSAlan Somers close(m_kq); 5109821f1d3SAlan Somers } 5119821f1d3SAlan Somers 5126c0c3620SAlan Somers void MockFS::audit_request(const mockfs_buf_in &in, ssize_t buflen) { 513bf507497SAlan Somers uint32_t inlen = in.header.len; 514bf507497SAlan Somers size_t fih = sizeof(in.header); 515bf507497SAlan Somers switch (in.header.opcode) { 516bf507497SAlan Somers case FUSE_LOOKUP: 517bf507497SAlan Somers case FUSE_RMDIR: 518bf507497SAlan Somers case FUSE_SYMLINK: 519bf507497SAlan Somers case FUSE_UNLINK: 5206c0c3620SAlan Somers EXPECT_GT(inlen, fih) << "Missing request filename"; 5216c0c3620SAlan Somers // No redundant information for checking buflen 522bf507497SAlan Somers break; 523bf507497SAlan Somers case FUSE_FORGET: 5246c0c3620SAlan Somers EXPECT_EQ(inlen, fih + sizeof(in.body.forget)); 5256c0c3620SAlan Somers EXPECT_EQ((size_t)buflen, inlen); 526bf507497SAlan Somers break; 527bf507497SAlan Somers case FUSE_GETATTR: 5286c0c3620SAlan Somers EXPECT_EQ(inlen, fih + sizeof(in.body.getattr)); 5296c0c3620SAlan Somers EXPECT_EQ((size_t)buflen, inlen); 530bf507497SAlan Somers break; 531bf507497SAlan Somers case FUSE_SETATTR: 5326c0c3620SAlan Somers EXPECT_EQ(inlen, fih + sizeof(in.body.setattr)); 5336c0c3620SAlan Somers EXPECT_EQ((size_t)buflen, inlen); 534bf507497SAlan Somers break; 535bf507497SAlan Somers case FUSE_READLINK: 5366c0c3620SAlan Somers EXPECT_EQ(inlen, fih) << "Unexpected request body"; 5376c0c3620SAlan Somers EXPECT_EQ((size_t)buflen, inlen); 538bf507497SAlan Somers break; 539bf507497SAlan Somers case FUSE_MKNOD: 540bf507497SAlan Somers { 541bf507497SAlan Somers size_t s; 542bf507497SAlan Somers if (m_kernel_minor_version >= 12) 543bf507497SAlan Somers s = sizeof(in.body.mknod); 544bf507497SAlan Somers else 545bf507497SAlan Somers s = FUSE_COMPAT_MKNOD_IN_SIZE; 5466c0c3620SAlan Somers EXPECT_GE(inlen, fih + s) << "Missing request body"; 5476c0c3620SAlan Somers EXPECT_GT(inlen, fih + s) << "Missing request filename"; 5486c0c3620SAlan Somers // No redundant information for checking buflen 549bf507497SAlan Somers break; 550bf507497SAlan Somers } 551bf507497SAlan Somers case FUSE_MKDIR: 5526c0c3620SAlan Somers EXPECT_GE(inlen, fih + sizeof(in.body.mkdir)) << 553bf507497SAlan Somers "Missing request body"; 5546c0c3620SAlan Somers EXPECT_GT(inlen, fih + sizeof(in.body.mkdir)) << 555bf507497SAlan Somers "Missing request filename"; 5566c0c3620SAlan Somers // No redundant information for checking buflen 557bf507497SAlan Somers break; 558bf507497SAlan Somers case FUSE_RENAME: 5596c0c3620SAlan Somers EXPECT_GE(inlen, fih + sizeof(in.body.rename)) << 560bf507497SAlan Somers "Missing request body"; 5616c0c3620SAlan Somers EXPECT_GT(inlen, fih + sizeof(in.body.rename)) << 562bf507497SAlan Somers "Missing request filename"; 5636c0c3620SAlan Somers // No redundant information for checking buflen 564bf507497SAlan Somers break; 565bf507497SAlan Somers case FUSE_LINK: 5666c0c3620SAlan Somers EXPECT_GE(inlen, fih + sizeof(in.body.link)) << 567bf507497SAlan Somers "Missing request body"; 5686c0c3620SAlan Somers EXPECT_GT(inlen, fih + sizeof(in.body.link)) << 569bf507497SAlan Somers "Missing request filename"; 5706c0c3620SAlan Somers // No redundant information for checking buflen 571bf507497SAlan Somers break; 572bf507497SAlan Somers case FUSE_OPEN: 5736c0c3620SAlan Somers EXPECT_EQ(inlen, fih + sizeof(in.body.open)); 5746c0c3620SAlan Somers EXPECT_EQ((size_t)buflen, inlen); 575bf507497SAlan Somers break; 576bf507497SAlan Somers case FUSE_READ: 5776c0c3620SAlan Somers EXPECT_EQ(inlen, fih + sizeof(in.body.read)); 5786c0c3620SAlan Somers EXPECT_EQ((size_t)buflen, inlen); 579bf507497SAlan Somers break; 580bf507497SAlan Somers case FUSE_WRITE: 581bf507497SAlan Somers { 582bf507497SAlan Somers size_t s; 583bf507497SAlan Somers 584bf507497SAlan Somers if (m_kernel_minor_version >= 9) 585bf507497SAlan Somers s = sizeof(in.body.write); 586bf507497SAlan Somers else 587bf507497SAlan Somers s = FUSE_COMPAT_WRITE_IN_SIZE; 588bf507497SAlan Somers // I suppose a 0-byte write should be allowed 5896c0c3620SAlan Somers EXPECT_GE(inlen, fih + s) << "Missing request body"; 5906c0c3620SAlan Somers EXPECT_EQ((size_t)buflen, fih + s + in.body.write.size); 591bf507497SAlan Somers break; 592bf507497SAlan Somers } 593bf507497SAlan Somers case FUSE_DESTROY: 594bf507497SAlan Somers case FUSE_STATFS: 5956c0c3620SAlan Somers EXPECT_EQ(inlen, fih); 5966c0c3620SAlan Somers EXPECT_EQ((size_t)buflen, inlen); 597bf507497SAlan Somers break; 598bf507497SAlan Somers case FUSE_RELEASE: 5996c0c3620SAlan Somers EXPECT_EQ(inlen, fih + sizeof(in.body.release)); 6006c0c3620SAlan Somers EXPECT_EQ((size_t)buflen, inlen); 601bf507497SAlan Somers break; 602bf507497SAlan Somers case FUSE_FSYNC: 603bf507497SAlan Somers case FUSE_FSYNCDIR: 6046c0c3620SAlan Somers EXPECT_EQ(inlen, fih + sizeof(in.body.fsync)); 6056c0c3620SAlan Somers EXPECT_EQ((size_t)buflen, inlen); 606bf507497SAlan Somers break; 607bf507497SAlan Somers case FUSE_SETXATTR: 6086c0c3620SAlan Somers EXPECT_GE(inlen, fih + sizeof(in.body.setxattr)) << 609bf507497SAlan Somers "Missing request body"; 6106c0c3620SAlan Somers EXPECT_GT(inlen, fih + sizeof(in.body.setxattr)) << 611bf507497SAlan Somers "Missing request attribute name"; 6126c0c3620SAlan Somers // No redundant information for checking buflen 613bf507497SAlan Somers break; 614bf507497SAlan Somers case FUSE_GETXATTR: 6156c0c3620SAlan Somers EXPECT_GE(inlen, fih + sizeof(in.body.getxattr)) << 616bf507497SAlan Somers "Missing request body"; 6176c0c3620SAlan Somers EXPECT_GT(inlen, fih + sizeof(in.body.getxattr)) << 618bf507497SAlan Somers "Missing request attribute name"; 6196c0c3620SAlan Somers // No redundant information for checking buflen 620bf507497SAlan Somers break; 621bf507497SAlan Somers case FUSE_LISTXATTR: 6226c0c3620SAlan Somers EXPECT_EQ(inlen, fih + sizeof(in.body.listxattr)); 6236c0c3620SAlan Somers EXPECT_EQ((size_t)buflen, inlen); 624bf507497SAlan Somers break; 625bf507497SAlan Somers case FUSE_REMOVEXATTR: 6266c0c3620SAlan Somers EXPECT_GT(inlen, fih) << "Missing request attribute name"; 6276c0c3620SAlan Somers // No redundant information for checking buflen 628bf507497SAlan Somers break; 629bf507497SAlan Somers case FUSE_FLUSH: 6306c0c3620SAlan Somers EXPECT_EQ(inlen, fih + sizeof(in.body.flush)); 6316c0c3620SAlan Somers EXPECT_EQ((size_t)buflen, inlen); 632bf507497SAlan Somers break; 633bf507497SAlan Somers case FUSE_INIT: 6346c0c3620SAlan Somers EXPECT_EQ(inlen, fih + sizeof(in.body.init)); 6356c0c3620SAlan Somers EXPECT_EQ((size_t)buflen, inlen); 636bf507497SAlan Somers break; 637bf507497SAlan Somers case FUSE_OPENDIR: 6386c0c3620SAlan Somers EXPECT_EQ(inlen, fih + sizeof(in.body.opendir)); 6396c0c3620SAlan Somers EXPECT_EQ((size_t)buflen, inlen); 640bf507497SAlan Somers break; 641bf507497SAlan Somers case FUSE_READDIR: 6426c0c3620SAlan Somers EXPECT_EQ(inlen, fih + sizeof(in.body.readdir)); 6436c0c3620SAlan Somers EXPECT_EQ((size_t)buflen, inlen); 644bf507497SAlan Somers break; 645bf507497SAlan Somers case FUSE_RELEASEDIR: 6466c0c3620SAlan Somers EXPECT_EQ(inlen, fih + sizeof(in.body.releasedir)); 6476c0c3620SAlan Somers EXPECT_EQ((size_t)buflen, inlen); 648bf507497SAlan Somers break; 649bf507497SAlan Somers case FUSE_GETLK: 6506c0c3620SAlan Somers EXPECT_EQ(inlen, fih + sizeof(in.body.getlk)); 6516c0c3620SAlan Somers EXPECT_EQ((size_t)buflen, inlen); 652bf507497SAlan Somers break; 653bf507497SAlan Somers case FUSE_SETLK: 654bf507497SAlan Somers case FUSE_SETLKW: 6556c0c3620SAlan Somers EXPECT_EQ(inlen, fih + sizeof(in.body.setlk)); 6566c0c3620SAlan Somers EXPECT_EQ((size_t)buflen, inlen); 657bf507497SAlan Somers break; 658bf507497SAlan Somers case FUSE_ACCESS: 6596c0c3620SAlan Somers EXPECT_EQ(inlen, fih + sizeof(in.body.access)); 6606c0c3620SAlan Somers EXPECT_EQ((size_t)buflen, inlen); 661bf507497SAlan Somers break; 662bf507497SAlan Somers case FUSE_CREATE: 6636c0c3620SAlan Somers EXPECT_GE(inlen, fih + sizeof(in.body.create)) << 664bf507497SAlan Somers "Missing request body"; 6656c0c3620SAlan Somers EXPECT_GT(inlen, fih + sizeof(in.body.create)) << 666bf507497SAlan Somers "Missing request filename"; 6676c0c3620SAlan Somers // No redundant information for checking buflen 668bf507497SAlan Somers break; 669bf507497SAlan Somers case FUSE_INTERRUPT: 6706c0c3620SAlan Somers EXPECT_EQ(inlen, fih + sizeof(in.body.interrupt)); 6716c0c3620SAlan Somers EXPECT_EQ((size_t)buflen, inlen); 672bf507497SAlan Somers break; 673bf507497SAlan Somers case FUSE_BMAP: 6746c0c3620SAlan Somers EXPECT_EQ(inlen, fih + sizeof(in.body.bmap)); 6756c0c3620SAlan Somers EXPECT_EQ((size_t)buflen, inlen); 676bf507497SAlan Somers break; 67737df9d3bSAlan Somers case FUSE_LSEEK: 67837df9d3bSAlan Somers EXPECT_EQ(inlen, fih + sizeof(in.body.lseek)); 67937df9d3bSAlan Somers EXPECT_EQ((size_t)buflen, inlen); 68037df9d3bSAlan Somers break; 68192bbfe1fSAlan Somers case FUSE_COPY_FILE_RANGE: 68292bbfe1fSAlan Somers EXPECT_EQ(inlen, fih + sizeof(in.body.copy_file_range)); 68392bbfe1fSAlan Somers EXPECT_EQ(0ul, in.body.copy_file_range.flags); 68492bbfe1fSAlan Somers EXPECT_EQ((size_t)buflen, inlen); 68592bbfe1fSAlan Somers break; 686bf507497SAlan Somers case FUSE_NOTIFY_REPLY: 687bf507497SAlan Somers case FUSE_BATCH_FORGET: 688bf507497SAlan Somers case FUSE_FALLOCATE: 689bf507497SAlan Somers case FUSE_IOCTL: 690bf507497SAlan Somers case FUSE_POLL: 691bf507497SAlan Somers case FUSE_READDIRPLUS: 692bf507497SAlan Somers FAIL() << "Unsupported opcode?"; 693bf507497SAlan Somers default: 694bf507497SAlan Somers FAIL() << "Unknown opcode " << in.header.opcode; 695bf507497SAlan Somers } 696bf507497SAlan Somers } 697bf507497SAlan Somers 6989821f1d3SAlan Somers void MockFS::init(uint32_t flags) { 6996c0c3620SAlan Somers ssize_t buflen; 7006c0c3620SAlan Somers 70129edc611SAlan Somers std::unique_ptr<mockfs_buf_in> in(new mockfs_buf_in); 70229edc611SAlan Somers std::unique_ptr<mockfs_buf_out> out(new mockfs_buf_out); 7039821f1d3SAlan Somers 7046c0c3620SAlan Somers read_request(*in, buflen); 7056c0c3620SAlan Somers audit_request(*in, buflen); 7069821f1d3SAlan Somers ASSERT_EQ(FUSE_INIT, in->header.opcode); 7079821f1d3SAlan Somers 7089821f1d3SAlan Somers out->header.unique = in->header.unique; 7099821f1d3SAlan Somers out->header.error = 0; 7109821f1d3SAlan Somers out->body.init.major = FUSE_KERNEL_VERSION; 71116bd2d47SAlan Somers out->body.init.minor = m_kernel_minor_version;; 7129821f1d3SAlan Somers out->body.init.flags = in->body.init.flags & flags; 7138eecd9ceSAlan Somers out->body.init.max_write = m_maxwrite; 7149821f1d3SAlan Somers out->body.init.max_readahead = m_maxreadahead; 71587ff949aSAlan Somers 71687ff949aSAlan Somers if (m_kernel_minor_version < 23) { 71787ff949aSAlan Somers SET_OUT_HEADER_LEN(*out, init_7_22); 71887ff949aSAlan Somers } else { 719fef46454SAlan Somers out->body.init.time_gran = m_time_gran; 72029edc611SAlan Somers SET_OUT_HEADER_LEN(*out, init); 72187ff949aSAlan Somers } 72287ff949aSAlan Somers 72329edc611SAlan Somers write(m_fuse_fd, out.get(), out->header.len); 7249821f1d3SAlan Somers } 7259821f1d3SAlan Somers 7269821f1d3SAlan Somers void MockFS::kill_daemon() { 72781a619c4SAlan Somers m_quit = true; 7288b73a4c5SAlan Somers if (m_daemon_id != NULL) 7299821f1d3SAlan Somers pthread_kill(m_daemon_id, SIGUSR1); 7308b73a4c5SAlan Somers // Closing the /dev/fuse file descriptor first allows unmount to 7318b73a4c5SAlan Somers // succeed even if the daemon doesn't correctly respond to commands 7328b73a4c5SAlan Somers // during the unmount sequence. 7339821f1d3SAlan Somers close(m_fuse_fd); 7348b73a4c5SAlan Somers m_fuse_fd = -1; 7359821f1d3SAlan Somers } 7369821f1d3SAlan Somers 7379821f1d3SAlan Somers void MockFS::loop() { 73829edc611SAlan Somers std::vector<std::unique_ptr<mockfs_buf_out>> out; 7399821f1d3SAlan Somers 74029edc611SAlan Somers std::unique_ptr<mockfs_buf_in> in(new mockfs_buf_in); 7419821f1d3SAlan Somers ASSERT_TRUE(in != NULL); 74281a619c4SAlan Somers while (!m_quit) { 7436c0c3620SAlan Somers ssize_t buflen; 7446c0c3620SAlan Somers 74529edc611SAlan Somers bzero(in.get(), sizeof(*in)); 7466c0c3620SAlan Somers read_request(*in, buflen); 74781a619c4SAlan Somers if (m_quit) 7489821f1d3SAlan Somers break; 7499821f1d3SAlan Somers if (verbosity > 0) 7506c0c3620SAlan Somers debug_request(*in, buflen); 7516c0c3620SAlan Somers audit_request(*in, buflen); 7529821f1d3SAlan Somers if (pid_ok((pid_t)in->header.pid)) { 75329edc611SAlan Somers process(*in, out); 7549821f1d3SAlan Somers } else { 7559821f1d3SAlan Somers /* 7569821f1d3SAlan Somers * Reject any requests from unknown processes. Because 7579821f1d3SAlan Somers * we actually do mount a filesystem, plenty of 7589821f1d3SAlan Somers * unrelated system daemons may try to access it. 7599821f1d3SAlan Somers */ 76099cf7bffSAlan Somers if (verbosity > 1) 76199cf7bffSAlan Somers printf("\tREJECTED (wrong pid %d)\n", 76299cf7bffSAlan Somers in->header.pid); 76329edc611SAlan Somers process_default(*in, out); 7649821f1d3SAlan Somers } 76529edc611SAlan Somers for (auto &it: out) 76629edc611SAlan Somers write_response(*it); 7679821f1d3SAlan Somers out.clear(); 7689821f1d3SAlan Somers } 7699821f1d3SAlan Somers } 7709821f1d3SAlan Somers 771c2d70d6eSAlan Somers int MockFS::notify_inval_entry(ino_t parent, const char *name, size_t namelen) 772c2d70d6eSAlan Somers { 773c2d70d6eSAlan Somers std::unique_ptr<mockfs_buf_out> out(new mockfs_buf_out); 774c2d70d6eSAlan Somers 775c2d70d6eSAlan Somers out->header.unique = 0; /* 0 means asynchronous notification */ 776c2d70d6eSAlan Somers out->header.error = FUSE_NOTIFY_INVAL_ENTRY; 777c2d70d6eSAlan Somers out->body.inval_entry.parent = parent; 778c2d70d6eSAlan Somers out->body.inval_entry.namelen = namelen; 779c2d70d6eSAlan Somers strlcpy((char*)&out->body.bytes + sizeof(out->body.inval_entry), 780c2d70d6eSAlan Somers name, sizeof(out->body.bytes) - sizeof(out->body.inval_entry)); 781c2d70d6eSAlan Somers out->header.len = sizeof(out->header) + sizeof(out->body.inval_entry) + 782c2d70d6eSAlan Somers namelen; 783c2d70d6eSAlan Somers debug_response(*out); 784c2d70d6eSAlan Somers write_response(*out); 785c2d70d6eSAlan Somers return 0; 786c2d70d6eSAlan Somers } 787c2d70d6eSAlan Somers 788eae1ae13SAlan Somers int MockFS::notify_inval_inode(ino_t ino, off_t off, ssize_t len) 789eae1ae13SAlan Somers { 790eae1ae13SAlan Somers std::unique_ptr<mockfs_buf_out> out(new mockfs_buf_out); 791eae1ae13SAlan Somers 792eae1ae13SAlan Somers out->header.unique = 0; /* 0 means asynchronous notification */ 793eae1ae13SAlan Somers out->header.error = FUSE_NOTIFY_INVAL_INODE; 794eae1ae13SAlan Somers out->body.inval_inode.ino = ino; 795eae1ae13SAlan Somers out->body.inval_inode.off = off; 796eae1ae13SAlan Somers out->body.inval_inode.len = len; 797eae1ae13SAlan Somers out->header.len = sizeof(out->header) + sizeof(out->body.inval_inode); 798eae1ae13SAlan Somers debug_response(*out); 799eae1ae13SAlan Somers write_response(*out); 800eae1ae13SAlan Somers return 0; 801eae1ae13SAlan Somers } 802eae1ae13SAlan Somers 8035a0b9a27SAlan Somers int MockFS::notify_store(ino_t ino, off_t off, const void* data, ssize_t size) 8047cbb8e8aSAlan Somers { 8057cbb8e8aSAlan Somers std::unique_ptr<mockfs_buf_out> out(new mockfs_buf_out); 8067cbb8e8aSAlan Somers 8077cbb8e8aSAlan Somers out->header.unique = 0; /* 0 means asynchronous notification */ 8087cbb8e8aSAlan Somers out->header.error = FUSE_NOTIFY_STORE; 8097cbb8e8aSAlan Somers out->body.store.nodeid = ino; 8107cbb8e8aSAlan Somers out->body.store.offset = off; 8117cbb8e8aSAlan Somers out->body.store.size = size; 8127cbb8e8aSAlan Somers bcopy(data, (char*)&out->body.bytes + sizeof(out->body.store), size); 8137cbb8e8aSAlan Somers out->header.len = sizeof(out->header) + sizeof(out->body.store) + size; 8147cbb8e8aSAlan Somers debug_response(*out); 8157cbb8e8aSAlan Somers write_response(*out); 8167cbb8e8aSAlan Somers return 0; 8177cbb8e8aSAlan Somers } 8187cbb8e8aSAlan Somers 8199821f1d3SAlan Somers bool MockFS::pid_ok(pid_t pid) { 8209821f1d3SAlan Somers if (pid == m_pid) { 8219821f1d3SAlan Somers return (true); 82291ff3a0dSAlan Somers } else if (pid == m_child_pid) { 82391ff3a0dSAlan Somers return (true); 8249821f1d3SAlan Somers } else { 8259821f1d3SAlan Somers struct kinfo_proc *ki; 8269821f1d3SAlan Somers bool ok = false; 8279821f1d3SAlan Somers 8289821f1d3SAlan Somers ki = kinfo_getproc(pid); 8299821f1d3SAlan Somers if (ki == NULL) 8309821f1d3SAlan Somers return (false); 8319821f1d3SAlan Somers /* 8329821f1d3SAlan Somers * Allow access by the aio daemon processes so that our tests 8339821f1d3SAlan Somers * can use aio functions 8349821f1d3SAlan Somers */ 8359821f1d3SAlan Somers if (0 == strncmp("aiod", ki->ki_comm, 4)) 8369821f1d3SAlan Somers ok = true; 8379821f1d3SAlan Somers free(ki); 8389821f1d3SAlan Somers return (ok); 8399821f1d3SAlan Somers } 8409821f1d3SAlan Somers } 8419821f1d3SAlan Somers 84229edc611SAlan Somers void MockFS::process_default(const mockfs_buf_in& in, 84329edc611SAlan Somers std::vector<std::unique_ptr<mockfs_buf_out>> &out) 8449821f1d3SAlan Somers { 84529edc611SAlan Somers std::unique_ptr<mockfs_buf_out> out0(new mockfs_buf_out); 84629edc611SAlan Somers out0->header.unique = in.header.unique; 8479821f1d3SAlan Somers out0->header.error = -EOPNOTSUPP; 8489821f1d3SAlan Somers out0->header.len = sizeof(out0->header); 84929edc611SAlan Somers out.push_back(std::move(out0)); 8509821f1d3SAlan Somers } 8519821f1d3SAlan Somers 8526c0c3620SAlan Somers void MockFS::read_request(mockfs_buf_in &in, ssize_t &res) { 85377fbe694SAlan Somers int nready = 0; 8543429092cSAlan Somers fd_set readfds; 8553429092cSAlan Somers pollfd fds[1]; 8563429092cSAlan Somers struct kevent changes[1]; 8573429092cSAlan Somers struct kevent events[1]; 85877fbe694SAlan Somers struct timespec timeout_ts; 85977fbe694SAlan Somers struct timeval timeout_tv; 86077fbe694SAlan Somers const int timeout_ms = 999; 86177fbe694SAlan Somers int timeout_int, nfds; 8629821f1d3SAlan Somers 8633429092cSAlan Somers switch (m_pm) { 8643429092cSAlan Somers case BLOCKING: 8653429092cSAlan Somers break; 8663429092cSAlan Somers case KQ: 86777fbe694SAlan Somers timeout_ts.tv_sec = 0; 86877fbe694SAlan Somers timeout_ts.tv_nsec = timeout_ms * 1'000'000; 86977fbe694SAlan Somers while (nready == 0) { 87077fbe694SAlan Somers EV_SET(&changes[0], m_fuse_fd, EVFILT_READ, EV_ADD, 0, 87177fbe694SAlan Somers 0, 0); 87277fbe694SAlan Somers nready = kevent(m_kq, &changes[0], 1, &events[0], 1, 87377fbe694SAlan Somers &timeout_ts); 8743429092cSAlan Somers if (m_quit) 8753429092cSAlan Somers return; 87677fbe694SAlan Somers } 8773429092cSAlan Somers ASSERT_LE(0, nready) << strerror(errno); 8783429092cSAlan Somers ASSERT_EQ(events[0].ident, (uintptr_t)m_fuse_fd); 8793429092cSAlan Somers if (events[0].flags & EV_ERROR) 8803429092cSAlan Somers FAIL() << strerror(events[0].data); 8813429092cSAlan Somers else if (events[0].flags & EV_EOF) 8823429092cSAlan Somers FAIL() << strerror(events[0].fflags); 8830a7c63e0SAlan Somers m_nready = events[0].data; 8843429092cSAlan Somers break; 8853429092cSAlan Somers case POLL: 88677fbe694SAlan Somers timeout_int = timeout_ms; 8873429092cSAlan Somers fds[0].fd = m_fuse_fd; 8883429092cSAlan Somers fds[0].events = POLLIN; 88977fbe694SAlan Somers while (nready == 0) { 89077fbe694SAlan Somers nready = poll(fds, 1, timeout_int); 8913429092cSAlan Somers if (m_quit) 8923429092cSAlan Somers return; 89377fbe694SAlan Somers } 8943429092cSAlan Somers ASSERT_LE(0, nready) << strerror(errno); 8953429092cSAlan Somers ASSERT_TRUE(fds[0].revents & POLLIN); 8963429092cSAlan Somers break; 8973429092cSAlan Somers case SELECT: 89877fbe694SAlan Somers timeout_tv.tv_sec = 0; 89977fbe694SAlan Somers timeout_tv.tv_usec = timeout_ms * 1'000; 90077fbe694SAlan Somers nfds = m_fuse_fd + 1; 90177fbe694SAlan Somers while (nready == 0) { 9023429092cSAlan Somers FD_ZERO(&readfds); 9033429092cSAlan Somers FD_SET(m_fuse_fd, &readfds); 90477fbe694SAlan Somers nready = select(nfds, &readfds, NULL, NULL, 90577fbe694SAlan Somers &timeout_tv); 9063429092cSAlan Somers if (m_quit) 9073429092cSAlan Somers return; 90877fbe694SAlan Somers } 9093429092cSAlan Somers ASSERT_LE(0, nready) << strerror(errno); 9103429092cSAlan Somers ASSERT_TRUE(FD_ISSET(m_fuse_fd, &readfds)); 9113429092cSAlan Somers break; 9123429092cSAlan Somers default: 9133429092cSAlan Somers FAIL() << "not yet implemented"; 9143429092cSAlan Somers } 91529edc611SAlan Somers res = read(m_fuse_fd, &in, sizeof(in)); 9163429092cSAlan Somers 917b690d120SAlan Somers if (res < 0 && !m_quit) { 918b690d120SAlan Somers m_quit = true; 9198e765737SAlan Somers FAIL() << "read: " << strerror(errno); 920b690d120SAlan Somers } 92129edc611SAlan Somers ASSERT_TRUE(res >= static_cast<ssize_t>(sizeof(in.header)) || m_quit); 922bf507497SAlan Somers /* 923bf507497SAlan Somers * Inconsistently, fuse_in_header.len is the size of the entire 924bf507497SAlan Somers * request,including header, even though fuse_out_header.len excludes 925bf507497SAlan Somers * the size of the header. 926bf507497SAlan Somers */ 92738a3e0bdSAlan Somers ASSERT_TRUE(res == static_cast<ssize_t>(in.header.len) || m_quit); 9289821f1d3SAlan Somers } 9299821f1d3SAlan Somers 93029edc611SAlan Somers void MockFS::write_response(const mockfs_buf_out &out) { 9313429092cSAlan Somers fd_set writefds; 9323429092cSAlan Somers pollfd fds[1]; 9333429092cSAlan Somers int nready, nfds; 9343429092cSAlan Somers ssize_t r; 9353429092cSAlan Somers 9363429092cSAlan Somers switch (m_pm) { 9373429092cSAlan Somers case BLOCKING: 9383429092cSAlan Somers case KQ: /* EVFILT_WRITE is not supported */ 9393429092cSAlan Somers break; 9403429092cSAlan Somers case POLL: 9413429092cSAlan Somers fds[0].fd = m_fuse_fd; 9423429092cSAlan Somers fds[0].events = POLLOUT; 9433429092cSAlan Somers nready = poll(fds, 1, INFTIM); 9443429092cSAlan Somers ASSERT_LE(0, nready) << strerror(errno); 9453429092cSAlan Somers ASSERT_EQ(1, nready) << "NULL timeout expired?"; 9463429092cSAlan Somers ASSERT_TRUE(fds[0].revents & POLLOUT); 9473429092cSAlan Somers break; 9483429092cSAlan Somers case SELECT: 9493429092cSAlan Somers FD_ZERO(&writefds); 9503429092cSAlan Somers FD_SET(m_fuse_fd, &writefds); 9513429092cSAlan Somers nfds = m_fuse_fd + 1; 9523429092cSAlan Somers nready = select(nfds, NULL, &writefds, NULL, NULL); 9533429092cSAlan Somers ASSERT_LE(0, nready) << strerror(errno); 9543429092cSAlan Somers ASSERT_EQ(1, nready) << "NULL timeout expired?"; 9553429092cSAlan Somers ASSERT_TRUE(FD_ISSET(m_fuse_fd, &writefds)); 9563429092cSAlan Somers break; 9573429092cSAlan Somers default: 9583429092cSAlan Somers FAIL() << "not yet implemented"; 9593429092cSAlan Somers } 96029edc611SAlan Somers r = write(m_fuse_fd, &out, out.header.len); 9613429092cSAlan Somers ASSERT_TRUE(r > 0 || errno == EAGAIN) << strerror(errno); 9623429092cSAlan Somers } 9633429092cSAlan Somers 9649821f1d3SAlan Somers void* MockFS::service(void *pthr_data) { 9659821f1d3SAlan Somers MockFS *mock_fs = (MockFS*)pthr_data; 9669821f1d3SAlan Somers 9679821f1d3SAlan Somers mock_fs->loop(); 9689821f1d3SAlan Somers 9699821f1d3SAlan Somers return (NULL); 9709821f1d3SAlan Somers } 9719821f1d3SAlan Somers 9729821f1d3SAlan Somers void MockFS::unmount() { 9739821f1d3SAlan Somers ::unmount("mountpoint", 0); 9749821f1d3SAlan Somers } 975