| /** |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with this |
| * work for additional information regarding copyright ownership. The ASF |
| * licenses this file to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * <p> |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * <p> |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS,WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations under |
| * the License. |
| */ |
| |
| |
| #define FUSE_USE_VERSION 31 |
| |
| #ifdef HAVE_CONFIG_H |
| #include <config.h> |
| #endif |
| |
| #ifdef linux |
| /* For pread()/pwrite()/utimensat() */ |
| #define _XOPEN_SOURCE 700 |
| #endif |
| |
| #include <libgen.h> |
| #include <stdlib.h> |
| |
| #include <fuse3/fuse.h> |
| #include <stdio.h> |
| #include <ctime> |
| #include <string.h> |
| #include <unistd.h> |
| #include <fcntl.h> |
| #include <sys/stat.h> |
| #include <dirent.h> |
| #include <errno.h> |
| #ifdef __FreeBSD__ |
| #include <sys/socket.h> |
| #include <sys/un.h> |
| #endif |
| #include <sys/time.h> |
| |
| |
| #ifdef HAVE_SETXATTR |
| #include <sys/xattr.h> |
| #endif |
| #include "failure_injector_fs.h" |
| #include "failure_injector.h" |
| #include "run_grpc_service.h" |
| #include <string> |
| #include <iostream> |
| #include <sstream> |
| #include <strings.h> |
| #include <thread> |
| #include <cstdio> |
| |
| using NoiseInjector::FailureInjector; |
| using NoiseInjector::RunGrpcService; |
| |
| using namespace std; |
| using namespace NoiseInjector::FileSystem; |
| |
| #define LOGFILE "/var/log/noise_injector_log.txt" |
| |
| struct fuse_operations FailureInjectorFs::mFuseOperationsVec; |
| FailureInjector *FailureInjectorFs::mFailureInjector = NULL; |
| RunGrpcService *FailureInjectorFs::mGrpcSever = NULL; |
| |
| FailureInjectorFs::FailureInjectorFs(FailureInjector *injector) |
| { |
| mFailureInjector = injector; |
| mGrpcSever = new RunGrpcService(mFailureInjector); |
| } |
| |
| int FailureInjectorFs::mknod_wrapper( |
| int dirfd, |
| const char *path, |
| const char *link, |
| int mode, |
| dev_t rdev) |
| { |
| int res; |
| |
| if (S_ISREG(mode)) { |
| res = openat(dirfd, path, O_CREAT | O_EXCL | O_WRONLY, mode); |
| if (res >= 0) |
| res = close(res); |
| } else if (S_ISDIR(mode)) { |
| res = mkdirat(dirfd, path, mode); |
| } else if (S_ISLNK(mode) && link != NULL) { |
| res = symlinkat(link, dirfd, path); |
| } else if (S_ISFIFO(mode)) { |
| res = mkfifoat(dirfd, path, mode); |
| } else { |
| res = mknodat(dirfd, path, mode, rdev); |
| } |
| |
| return res; |
| } |
| |
| void *FailureInjectorFs::fifs_init( |
| struct fuse_conn_info *conn, |
| struct fuse_config *cfg) |
| { |
| extern void RunServer(); |
| (void) conn; |
| cfg->use_ino = 1; |
| |
| std::freopen(LOGFILE, "w", stdout); |
| |
| /* |
| * Pick up changes from lower filesystem right away. This is |
| * also necessary for better hardlink support. When the kernel |
| * calls the unlink() handler, it does not know the inode of |
| * the to-be-removed entry and can therefore not invalidate |
| * the cache of the associated inode - resulting in an |
| * incorrect st_nlink value being reported for any remaining |
| * hardlinks to this inode. |
| */ |
| cfg->entry_timeout = 0; |
| cfg->attr_timeout = 0; |
| cfg->negative_timeout = 0; |
| |
| /* Create a seperate GRPC server thread to accept failure injection. */ |
| std::thread th(&RunGrpcService::RunServer, mGrpcSever); |
| th.detach(); |
| |
| return NULL; |
| } |
| |
| int FailureInjectorFs::fifs_getattr( |
| const char *path, |
| struct stat *stbuf, |
| struct fuse_file_info *fi) |
| { |
| (void) fi; |
| int res; |
| int injected_error = 0; |
| |
| if (CheckForInjectedError(path,"GETATTR", &injected_error)) { |
| cout << "Returning Injected error " << injected_error << "\n"; |
| return -injected_error; |
| } |
| |
| res = lstat(path, stbuf); |
| if (res == -1) |
| return -errno; |
| |
| return 0; |
| } |
| |
| int FailureInjectorFs::fifs_access( |
| const char *path, |
| int mask) |
| { |
| int res; |
| int injected_error = 0; |
| |
| if (CheckForInjectedError(path,"ACCESS", &injected_error)) { |
| cout << "Returning Injected error " << injected_error << "\n"; |
| return -injected_error; |
| } |
| |
| res = access(path, mask); |
| if (res == -1) |
| return -errno; |
| |
| return 0; |
| } |
| |
| int FailureInjectorFs::fifs_readlink( |
| const char *path, |
| char *buf, |
| size_t size) |
| { |
| int res; |
| int injected_error = 0; |
| |
| if (CheckForInjectedError(path,"READLINK", &injected_error)) { |
| cout << "Returning Injected error " << injected_error << "\n"; |
| return -injected_error; |
| } |
| |
| res = readlink(path, buf, size - 1); |
| if (res == -1) |
| return -errno; |
| |
| buf[res] = '\0'; |
| return 0; |
| } |
| |
| int FailureInjectorFs::fifs_readdir( |
| const char *path, |
| void *buf, |
| fuse_fill_dir_t filler, |
| off_t offset, |
| struct fuse_file_info *fi, |
| enum fuse_readdir_flags flags) |
| { |
| DIR *dp; |
| struct dirent *de; |
| int injected_error = 0; |
| |
| (void) offset; |
| (void) fi; |
| (void) flags; |
| |
| if (CheckForInjectedError(path,"READDIR", &injected_error)) { |
| cout << "Returning Injected error " << injected_error << "\n"; |
| return -injected_error; |
| } |
| |
| dp = opendir(path); |
| if (dp == NULL) |
| return -errno; |
| |
| while ((de = readdir(dp)) != NULL) { |
| struct stat st; |
| memset(&st, 0, sizeof(st)); |
| st.st_ino = de->d_ino; |
| st.st_mode = de->d_type << 12; |
| if (filler(buf, de->d_name, &st, 0, (fuse_fill_dir_flags)0)) |
| break; |
| } |
| |
| closedir(dp); |
| return 0; |
| } |
| |
| int FailureInjectorFs::fifs_mknod( |
| const char *path, |
| mode_t mode, |
| dev_t rdev) |
| { |
| int res; |
| int injected_error = 0; |
| |
| if (CheckForInjectedError(path,"MKNOD", &injected_error)) { |
| cout << "Returning Injected error " << injected_error << "\n"; |
| return -injected_error; |
| } |
| |
| res = mknod_wrapper(AT_FDCWD, path, NULL, mode, rdev); |
| if (res == -1) |
| return -errno; |
| |
| return 0; |
| } |
| |
| int FailureInjectorFs::fifs_mkdir( |
| const char *path, |
| mode_t mode) |
| { |
| int res; |
| int injected_error = 0; |
| |
| if (CheckForInjectedError(path,"MKDIR", &injected_error)) { |
| cout << "Returning Injected error " << injected_error << "\n"; |
| return -injected_error; |
| } |
| |
| res = mkdir(path, mode); |
| if (res == -1) |
| return -errno; |
| |
| return 0; |
| } |
| |
| int FailureInjectorFs::fifs_unlink(const char *path) |
| { |
| int res; |
| int injected_error = 0; |
| |
| if (CheckForInjectedError(path,"UNLINK", &injected_error)) { |
| cout << "Returning Injected error " << injected_error << "\n"; |
| return -injected_error; |
| } |
| |
| res = unlink(path); |
| if (res == -1) |
| return -errno; |
| |
| return 0; |
| } |
| |
| int FailureInjectorFs::fifs_rmdir(const char *path) |
| { |
| int res; |
| int injected_error = 0; |
| |
| if (CheckForInjectedError(path,"RMDIR", &injected_error)) { |
| cout << "Returning Injected error " << injected_error << "\n"; |
| return -injected_error; |
| } |
| |
| res = rmdir(path); |
| if (res == -1) |
| return -errno; |
| |
| return 0; |
| } |
| |
| int FailureInjectorFs::fifs_symlink( |
| const char *from, |
| const char *to) |
| { |
| int res; |
| int injected_error = 0; |
| |
| if (CheckForInjectedError(from, "SYMLINK", &injected_error)) { |
| cout << "Returning Injected error " << injected_error << "\n"; |
| return -injected_error; |
| } |
| |
| res = symlink(from, to); |
| if (res == -1) |
| return -errno; |
| |
| return 0; |
| } |
| |
| int FailureInjectorFs::fifs_rename( |
| const char *from, |
| const char *to, |
| unsigned int flags) |
| { |
| int res; |
| int injected_error = 0; |
| |
| if (CheckForInjectedError(from, "RENAME", &injected_error)) { |
| cout << "Returning Injected error " << injected_error << "\n"; |
| return -injected_error; |
| } |
| |
| if (flags) |
| return -EINVAL; |
| |
| res = rename(from, to); |
| if (res == -1) |
| return -errno; |
| |
| return 0; |
| } |
| |
| int FailureInjectorFs::fifs_link( |
| const char *from, |
| const char *to) |
| { |
| int res; |
| int injected_error = 0; |
| |
| if (CheckForInjectedError(from,"LINK", &injected_error)) { |
| cout << "Returning Injected error " << injected_error << "\n"; |
| return -injected_error; |
| } |
| |
| res = link(from, to); |
| if (res == -1) |
| return -errno; |
| |
| return 0; |
| } |
| |
| int FailureInjectorFs::fifs_chmod( |
| const char *path, |
| mode_t mode, |
| struct fuse_file_info *fi) |
| { |
| (void) fi; |
| int res; |
| int injected_error = 0; |
| |
| if (CheckForInjectedError(path,"CHMOD", &injected_error)) { |
| cout << "Returning Injected error " << injected_error << "\n"; |
| return -injected_error; |
| } |
| |
| res = chmod(path, mode); |
| if (res == -1) |
| return -errno; |
| |
| return 0; |
| } |
| |
| int FailureInjectorFs::fifs_chown( |
| const char *path, |
| uid_t uid, |
| gid_t gid, |
| struct fuse_file_info *fi) |
| { |
| (void) fi; |
| int res; |
| int injected_error = 0; |
| |
| if (CheckForInjectedError(path,"CHOWN", &injected_error)) { |
| cout << "Returning Injected error " << injected_error << "\n"; |
| return -injected_error; |
| } |
| |
| res = lchown(path, uid, gid); |
| if (res == -1) |
| return -errno; |
| |
| return 0; |
| } |
| |
| int FailureInjectorFs::fifs_truncate( |
| const char *path, |
| off_t size, |
| struct fuse_file_info *fi) |
| { |
| int res; |
| int injected_error = 0; |
| |
| if (CheckForInjectedError(path,"TRUNCATE", &injected_error)) { |
| cout << "Returning Injected error " << injected_error << "\n"; |
| return -injected_error; |
| } |
| |
| if (fi != NULL) |
| res = ftruncate(fi->fh, size); |
| else |
| res = truncate(path, size); |
| if (res == -1) |
| return -errno; |
| |
| return 0; |
| } |
| |
| #ifdef HAVE_UTIMENSAT |
| int FailureInjectorFs::fifs_utimens( |
| const char *path, |
| const struct timespec ts[2], |
| struct fuse_file_info *fi) |
| { |
| (void) fi; |
| int res; |
| int injected_error = 0; |
| |
| if (CheckForInjectedError(path,"UTIMENS", &injected_error)) { |
| cout << "Returning Injected error " << injected_error << "\n"; |
| return -injected_error; |
| } |
| |
| |
| /* don't use utime/utimes since they follow symlinks */ |
| res = utimensat(0, path, ts, AT_SYMLINK_NOFOLLOW); |
| if (res == -1) |
| return -errno; |
| |
| return 0; |
| } |
| #endif |
| |
| int FailureInjectorFs::fifs_create( |
| const char *path, |
| mode_t mode, |
| struct fuse_file_info *fi) |
| { |
| int res; |
| int injected_error = 0; |
| |
| if (CheckForInjectedError(path,"CREATE", &injected_error)) { |
| cout << "Returning Injected error " << injected_error << "\n"; |
| return -injected_error; |
| } |
| |
| res = open(path, fi->flags, mode); |
| if (res == -1) |
| return -errno; |
| |
| fi->fh = res; |
| return 0; |
| } |
| |
| int FailureInjectorFs::fifs_open( |
| const char *path, |
| struct fuse_file_info *fi) |
| { |
| int res; |
| int injected_error = 0; |
| |
| if (CheckForInjectedError(path,"OPEN", &injected_error)) { |
| cout << "Returning Injected error " << injected_error << "\n"; |
| return -injected_error; |
| } |
| |
| res = open(path, fi->flags); |
| if (res == -1) |
| return -errno; |
| |
| fi->fh = res; |
| return 0; |
| } |
| |
| bool FailureInjectorFs::CheckForInjectedError( |
| string path, |
| string op, |
| int *injected_error) |
| { |
| char *mpath = strdup(path.c_str()); |
| if (mFailureInjector == NULL) { |
| return false; |
| } |
| |
| auto failures = mFailureInjector->GetFailures(path, op); |
| while (failures == NULL) { |
| // Check if failures are injected in any of the parent directories. |
| char *dir = dirname(mpath); |
| failures = mFailureInjector->GetFailures(string(dir), op); |
| if ((failures == NULL) && (!strcmp(dir, ".") || !strcmp(dir, "/"))) { |
| free(mpath); |
| return false; |
| } |
| mpath = dir; |
| } |
| free(mpath); |
| |
| *injected_error = 0; |
| useconds_t delay = 1; |
| for (auto f : *failures) { |
| switch(f.code) { |
| case InjectedAction::DELAY: |
| delay = f.delay * MICROSECONDS_IN_A_SECOND; |
| break; |
| case InjectedAction::FAIL: |
| if (*injected_error != CORRUPT_DATA_ERROR_CODE) { |
| *injected_error = f.error_code; |
| } |
| break; |
| case InjectedAction::CORRUPT: |
| *injected_error = CORRUPT_DATA_ERROR_CODE; |
| break; |
| default: |
| // Ignore for now. |
| break; |
| } |
| } |
| // First create the delay. |
| usleep(delay); |
| |
| if (*injected_error) { |
| return true; |
| } |
| return false; |
| } |
| |
| void FailureInjectorFs::FillCorruptData( |
| char *buf, |
| size_t size) |
| { |
| // For now just fill with some pattern based on input. |
| // TBD : Fill with random data pattern. |
| for (size_t i = 0; i < size; ++ i) { |
| buf[i] = buf[i] + 2; |
| } |
| } |
| |
| int FailureInjectorFs::fifs_read( |
| const char *path, |
| char *buf, |
| size_t size, |
| off_t offset, |
| struct fuse_file_info *fi) |
| { |
| int fd; |
| int res; |
| int injected_error = 0; |
| |
| if (CheckForInjectedError(path, "READ", &injected_error)) { |
| cout << "Returning Injected error " << injected_error << "\n"; |
| if (injected_error != CORRUPT_DATA_ERROR_CODE) { |
| return -injected_error; |
| } |
| } |
| |
| if(fi == NULL) |
| fd = open(path, O_RDONLY); |
| else |
| fd = fi->fh; |
| |
| if (fd == -1) |
| return -errno; |
| |
| res = pread(fd, buf, size, offset); |
| if (res == -1) |
| res = -errno; |
| |
| if(fi == NULL) |
| close(fd); |
| if ((res != -1) && (injected_error == CORRUPT_DATA_ERROR_CODE)) { |
| FillCorruptData(buf, size); |
| return res; |
| } |
| return res; |
| } |
| |
| int FailureInjectorFs::fifs_write( |
| const char *path, |
| const char *buf, |
| size_t size, |
| off_t offset, |
| struct fuse_file_info *fi) |
| { |
| int fd; |
| int res; |
| int injected_error = 0; |
| (void) fi; |
| |
| if (CheckForInjectedError(path, "WRITE", &injected_error)) { |
| cout << "Returning Injected error " << injected_error << "\n"; |
| if (injected_error != CORRUPT_DATA_ERROR_CODE) { |
| return -injected_error; |
| } else { |
| FillCorruptData(const_cast<char *>(buf), size); |
| } |
| } |
| |
| if(fi == NULL) |
| fd = open(path, O_WRONLY); |
| else |
| fd = fi->fh; |
| |
| if (fd == -1) |
| return -errno; |
| |
| res = pwrite(fd, buf, size, offset); |
| if (res == -1) |
| res = -errno; |
| |
| if(fi == NULL) |
| close(fd); |
| return res; |
| } |
| |
| int FailureInjectorFs::fifs_statfs( |
| const char *path, |
| struct statvfs *stbuf) |
| { |
| int res; |
| int injected_error = 0; |
| |
| if (CheckForInjectedError(path, "STATFS", &injected_error)) { |
| cout << "Returning Injected error " << injected_error << "\n"; |
| return -injected_error; |
| } |
| |
| res = statvfs(path, stbuf); |
| if (res == -1) |
| return -errno; |
| |
| return 0; |
| } |
| |
| int FailureInjectorFs::fifs_release( |
| const char *path, |
| struct fuse_file_info *fi) |
| { |
| (void) path; |
| close(fi->fh); |
| return 0; |
| } |
| |
| int FailureInjectorFs::fifs_fsync( |
| const char *path, |
| int isdatasync, |
| struct fuse_file_info *fi) |
| { |
| int injected_error = 0; |
| |
| if (CheckForInjectedError(path,"FSYNC", &injected_error)) { |
| cout << "Returning Injected error " << injected_error << "\n"; |
| return -injected_error; |
| } |
| |
| |
| (void) path; |
| (void) isdatasync; |
| (void) fi; |
| return 0; |
| } |
| |
| #ifdef HAVE_POSIX_FALLOCATE |
| int FailureInjectorFs::fifs_fallocate( |
| const char *path, |
| int mode, |
| off_t offset, |
| off_t length, |
| struct fuse_file_info *fi) |
| { |
| int fd; |
| int res; |
| int injected_error = 0; |
| |
| (void) fi; |
| |
| if (CheckForInjectedError(path,"FALLOCATE", &injected_error)) { |
| cout << "Returning Injected error " << injected_error << "\n"; |
| return -injected_error; |
| } |
| |
| if (mode) |
| return -EOPNOTSUPP; |
| |
| if(fi == NULL) |
| fd = open(path, O_WRONLY); |
| else |
| fd = fi->fh; |
| |
| if (fd == -1) |
| return -errno; |
| |
| res = -posix_fallocate(fd, offset, length); |
| |
| if(fi == NULL) |
| close(fd); |
| return res; |
| } |
| #endif |
| |
| #ifdef HAVE_SETXATTR |
| /* xattr operations are optional and can safely be left unimplemented */ |
| int FailureInjectorFs::fifs_setxattr( |
| const char *path, |
| const char *name, |
| const char *value, |
| size_t size, |
| int flags) |
| { |
| int injected_error = 0; |
| |
| if (CheckForInjectedError(path,"SETXATTR", &injected_error)) { |
| cout << "Returning Injected error " << injected_error << "\n"; |
| return -injected_error; |
| } |
| |
| int res = lsetxattr(path, name, value, size, flags); |
| if (res == -1) |
| return -errno; |
| return 0; |
| } |
| |
| int FailureInjectorFs::fifs_getxattr( |
| const char *path, |
| const char *name, |
| char *value, |
| size_t size) |
| { |
| int injected_error = 0; |
| |
| if (CheckForInjectedError(path,"GETXATTR", &injected_error)) { |
| cout << "Returning Injected error " << injected_error << "\n"; |
| return -injected_error; |
| } |
| |
| int res = lgetxattr(path, name, value, size); |
| if (res == -1) |
| return -errno; |
| return res; |
| } |
| |
| int FailureInjectorFs::fifs_listxattr( |
| const char *path, |
| char *list, |
| size_t size) |
| { |
| int injected_error = 0; |
| |
| if (CheckForInjectedError(path,"LISTXATTR", &injected_error)) { |
| cout << "Returning Injected error " << injected_error << "\n"; |
| return -injected_error; |
| } |
| |
| int res = llistxattr(path, list, size); |
| if (res == -1) |
| return -errno; |
| return res; |
| } |
| |
| int FailureInjectorFs::fifs_removexattr( |
| const char *path, |
| const char *name) |
| { |
| int injected_error = 0; |
| |
| if (CheckForInjectedError(path,"REMOVEXATTR", &injected_error)) { |
| cout << "Returning Injected error " << injected_error << "\n"; |
| return -injected_error; |
| } |
| |
| int res = lremovexattr(path, name); |
| if (res == -1) |
| return -errno; |
| return 0; |
| } |
| #endif /* HAVE_SETXATTR */ |
| |
| off_t FailureInjectorFs::fifs_lseek( |
| const char *path, |
| off_t off, |
| int whence, |
| struct fuse_file_info *fi) |
| { |
| int fd; |
| off_t res; |
| int injected_error = 0; |
| |
| if (CheckForInjectedError(path,"LSEEK", &injected_error)) { |
| cout << "Returning Injected error " << injected_error << "\n"; |
| return -injected_error; |
| } |
| |
| if (fi == NULL) |
| fd = open(path, O_RDONLY); |
| else |
| fd = fi->fh; |
| |
| if (fd == -1) |
| return -errno; |
| |
| res = lseek(fd, off, whence); |
| if (res == -1) |
| res = -errno; |
| |
| if (fi == NULL) |
| close(fd); |
| return res; |
| } |
| |
| void FailureInjectorFs::load_operations() { |
| mFuseOperationsVec.getattr = FailureInjectorFs::fifs_getattr; |
| mFuseOperationsVec.readlink = FailureInjectorFs::fifs_readlink; |
| mFuseOperationsVec.mknod = FailureInjectorFs::fifs_mknod; |
| mFuseOperationsVec.mkdir = FailureInjectorFs::fifs_mkdir; |
| mFuseOperationsVec.unlink = FailureInjectorFs::fifs_unlink; |
| mFuseOperationsVec.rmdir = FailureInjectorFs::fifs_rmdir; |
| mFuseOperationsVec.symlink = FailureInjectorFs::fifs_symlink; |
| mFuseOperationsVec.rename = FailureInjectorFs::fifs_rename; |
| mFuseOperationsVec.link = FailureInjectorFs::fifs_link; |
| mFuseOperationsVec.chmod = FailureInjectorFs::fifs_chmod; |
| mFuseOperationsVec.chown = FailureInjectorFs::fifs_chown; |
| mFuseOperationsVec.truncate = FailureInjectorFs::fifs_truncate; |
| mFuseOperationsVec.open = FailureInjectorFs::fifs_open; |
| mFuseOperationsVec.read = FailureInjectorFs::fifs_read; |
| mFuseOperationsVec.write = FailureInjectorFs::fifs_write; |
| mFuseOperationsVec.statfs = FailureInjectorFs::fifs_statfs; |
| mFuseOperationsVec.flush = NULL; |
| mFuseOperationsVec.release = FailureInjectorFs::fifs_release; |
| mFuseOperationsVec.fsync = FailureInjectorFs::fifs_fsync; |
| |
| #ifdef HAVE_SETXATTR |
| mFuseOperationsVec.setxattr = FailureInjectorFs::fifs_setxattr; |
| mFuseOperationsVec.getxattr = FailureInjectorFs::fifs_getxattr; |
| mFuseOperationsVec.listxattr = FailureInjectorFs::fifs_listxattr; |
| mFuseOperationsVec.removexattr = FailureInjectorFs::fifs_removexattr; |
| #else |
| mFuseOperationsVec.setxattr = NULL; |
| mFuseOperationsVec.getxattr = NULL; |
| mFuseOperationsVec.listxattr = NULL; |
| mFuseOperationsVec.removexattr = NULL; |
| #endif |
| |
| mFuseOperationsVec.opendir = NULL; |
| mFuseOperationsVec.readdir = FailureInjectorFs::fifs_readdir; |
| mFuseOperationsVec.releasedir = NULL; |
| mFuseOperationsVec.fsyncdir = NULL; |
| mFuseOperationsVec.init = FailureInjectorFs::fifs_init; |
| mFuseOperationsVec.destroy = NULL; |
| mFuseOperationsVec.access = FailureInjectorFs::fifs_access; |
| mFuseOperationsVec.create = FailureInjectorFs::fifs_create; |
| mFuseOperationsVec.lock = NULL; |
| |
| #ifdef HAVE_UTIMENSAT |
| mFuseOperationsVec.utimens = FailureInjectorFs::fifs_utimens; |
| #else |
| mFuseOperationsVec.utimens = NULL; |
| #endif |
| |
| mFuseOperationsVec.bmap = NULL; |
| mFuseOperationsVec.ioctl = NULL; |
| mFuseOperationsVec.poll = NULL; |
| mFuseOperationsVec.write_buf = NULL; |
| mFuseOperationsVec.read_buf = NULL; |
| mFuseOperationsVec.flock = NULL; |
| |
| #ifdef HAVE_POSIX_FALLOCATE |
| mFuseOperationsVec.fallocate = FailureInjectorFs::fifs_fallocate; |
| #else |
| mFuseOperationsVec.fallocate = NULL; |
| #endif |
| |
| mFuseOperationsVec.copy_file_range = NULL; |
| } |
| |
| const struct fuse_operations *FailureInjectorFs::getOperations() { |
| return &mFuseOperationsVec; |
| } |
| |
| int main(int argc, char *argv[]) |
| { |
| FailureInjector *injector = new FailureInjector(); |
| FailureInjectorFs noise_fs(injector); |
| |
| noise_fs.load_operations(); |
| umask(0); |
| fuse_main(argc, argv, noise_fs.getOperations(), NULL); |
| } |