mirror of
https://github.com/trapexit/mergerfs.git
synced 2026-10-26 10:51:52 -04:00
libfuse previously initialized its debug log filepath to "/dev/stderr", forcing the config layer to reopen stderr on every load whether or not the user asked for it. Default the libfuse log path to "" and have the mergerfs config layer only forward the request to libfuse when the user supplied an explicit path.
1979 lines
43 KiB
C++
1979 lines
43 KiB
C++
/*
|
|
ISC License
|
|
|
|
Copyright (c) 2026, Antonio SJ Musumeci <trapexit@spawn.link>
|
|
|
|
Permission to use, copy, modify, and/or distribute this software for any
|
|
purpose with or without fee is hereby granted, provided that the above
|
|
copyright notice and this permission notice appear in all copies.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
|
|
#ifndef _GNU_SOURCE
|
|
#define _GNU_SOURCE
|
|
#endif
|
|
|
|
#include "syslog.hpp"
|
|
|
|
#include "fuse_cfg.hpp"
|
|
#include "fuse_kernel.h"
|
|
|
|
#include "fmt/core.h"
|
|
#include "fmt/format.h"
|
|
|
|
#include <memory>
|
|
#include <string>
|
|
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
|
|
#define PARAM(inarg) (((char *)(inarg)) + sizeof(*(inarg)))
|
|
#define STRERR_BUF_SIZE 128
|
|
|
|
static
|
|
void
|
|
_fclose_deleter(FILE *f_)
|
|
{
|
|
if(f_ == nullptr)
|
|
return;
|
|
if(f_ == stdin)
|
|
return;
|
|
if(f_ == stdout)
|
|
return;
|
|
if(f_ == stderr)
|
|
return;
|
|
|
|
fclose(f_);
|
|
}
|
|
|
|
static
|
|
int
|
|
_debug_set_output_stderr()
|
|
{
|
|
auto new_log_file = std::shared_ptr<FILE>(stderr,[](FILE*){});
|
|
|
|
fuse_cfg.log_file(new_log_file);
|
|
fuse_cfg.log_filepath("");
|
|
|
|
return 0;
|
|
}
|
|
|
|
static
|
|
int
|
|
_debug_set_output_filepath(const std::string &filepath_)
|
|
{
|
|
FILE *tmp_new_file;
|
|
|
|
tmp_new_file = fopen(filepath_.c_str(),"a");
|
|
if(tmp_new_file == NULL)
|
|
return -errno;
|
|
|
|
setvbuf(tmp_new_file,NULL,_IOLBF,0);
|
|
|
|
auto new_log_file =
|
|
std::shared_ptr<FILE>(tmp_new_file,::_fclose_deleter);
|
|
|
|
fuse_cfg.log_file(new_log_file);
|
|
fuse_cfg.log_filepath(filepath_);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
fuse_debug_set_output(const std::string &filepath_)
|
|
{
|
|
if(filepath_.empty())
|
|
return _debug_set_output_stderr();
|
|
|
|
return _debug_set_output_filepath(filepath_.c_str());
|
|
}
|
|
|
|
static
|
|
uint64_t
|
|
_timestamp_ns(void)
|
|
{
|
|
struct timespec ts;
|
|
|
|
clock_gettime(CLOCK_MONOTONIC,&ts);
|
|
|
|
return ((uint64_t)ts.tv_sec * 1000000000ULL) + (uint64_t)ts.tv_nsec;
|
|
}
|
|
|
|
static
|
|
std::string
|
|
_quoted(const char *str_)
|
|
{
|
|
std::string out;
|
|
|
|
out += '"';
|
|
for(const char *p = str_; *p; p++)
|
|
{
|
|
if(*p == '"' || *p == '\\')
|
|
out += '\\';
|
|
out += *p;
|
|
}
|
|
out += '"';
|
|
|
|
return out;
|
|
}
|
|
|
|
static
|
|
std::string
|
|
_quoted(const char *data_,
|
|
size_t len_)
|
|
{
|
|
std::string out;
|
|
|
|
out += '"';
|
|
for(size_t i = 0; i < len_; i++)
|
|
{
|
|
if(data_[i] == '"' || data_[i] == '\\')
|
|
out += '\\';
|
|
out += data_[i];
|
|
}
|
|
out += '"';
|
|
|
|
return out;
|
|
}
|
|
|
|
static
|
|
const
|
|
char*
|
|
_open_accmode_to_str(const int flags_)
|
|
{
|
|
switch(flags_ & O_ACCMODE)
|
|
{
|
|
case O_RDWR:
|
|
return "O_RDWR";
|
|
case O_RDONLY:
|
|
return "O_RDONLY";
|
|
case O_WRONLY:
|
|
return "O_WRONLY";
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
#define FUSE_WRITE_FLAG_CASE(X) case FUSE_WRITE_##X: return #X
|
|
|
|
static
|
|
const
|
|
char*
|
|
_fuse_write_flag_to_str(const uint32_t offset_)
|
|
{
|
|
switch(1 << offset_)
|
|
{
|
|
FUSE_WRITE_FLAG_CASE(CACHE);
|
|
FUSE_WRITE_FLAG_CASE(LOCKOWNER);
|
|
FUSE_WRITE_FLAG_CASE(KILL_PRIV);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
#undef FUSE_WRITE_FLAG_CASE
|
|
|
|
#define OPEN_FLAG_CASE(X) case X: return #X
|
|
|
|
static
|
|
const
|
|
char*
|
|
_open_flag_to_str(const uint64_t offset_)
|
|
{
|
|
switch(1 << offset_)
|
|
{
|
|
OPEN_FLAG_CASE(O_APPEND);
|
|
OPEN_FLAG_CASE(O_ASYNC);
|
|
OPEN_FLAG_CASE(O_CLOEXEC);
|
|
OPEN_FLAG_CASE(O_CREAT);
|
|
OPEN_FLAG_CASE(O_DIRECT);
|
|
OPEN_FLAG_CASE(O_DIRECTORY);
|
|
#ifdef O_DSYNC
|
|
OPEN_FLAG_CASE(O_DSYNC);
|
|
#endif
|
|
OPEN_FLAG_CASE(O_EXCL);
|
|
#ifdef O_LARGEFILE
|
|
OPEN_FLAG_CASE(O_LARGEFILE);
|
|
#endif
|
|
#ifdef O_NOATIME
|
|
OPEN_FLAG_CASE(O_NOATIME);
|
|
#endif
|
|
OPEN_FLAG_CASE(O_NOCTTY);
|
|
OPEN_FLAG_CASE(O_NOFOLLOW);
|
|
OPEN_FLAG_CASE(O_NONBLOCK);
|
|
#ifdef O_PATH
|
|
OPEN_FLAG_CASE(O_PATH);
|
|
#endif
|
|
OPEN_FLAG_CASE(O_SYNC);
|
|
#ifdef O_TMPFILE
|
|
OPEN_FLAG_CASE(O_TMPFILE);
|
|
#endif
|
|
OPEN_FLAG_CASE(O_TRUNC);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
#undef OPEN_FLAG_CASE
|
|
|
|
#define FUSE_INIT_FLAG_CASE(X) case static_cast<uint64_t>(FUSE_##X): return #X
|
|
|
|
static
|
|
const
|
|
char*
|
|
_fuse_init_flag_name(const uint64_t flag_)
|
|
{
|
|
switch(flag_)
|
|
{
|
|
FUSE_INIT_FLAG_CASE(ASYNC_READ);
|
|
FUSE_INIT_FLAG_CASE(POSIX_LOCKS);
|
|
FUSE_INIT_FLAG_CASE(FILE_OPS);
|
|
FUSE_INIT_FLAG_CASE(ATOMIC_O_TRUNC);
|
|
FUSE_INIT_FLAG_CASE(EXPORT_SUPPORT);
|
|
FUSE_INIT_FLAG_CASE(BIG_WRITES);
|
|
FUSE_INIT_FLAG_CASE(DONT_MASK);
|
|
FUSE_INIT_FLAG_CASE(SPLICE_WRITE);
|
|
FUSE_INIT_FLAG_CASE(SPLICE_MOVE);
|
|
FUSE_INIT_FLAG_CASE(SPLICE_READ);
|
|
FUSE_INIT_FLAG_CASE(FLOCK_LOCKS);
|
|
FUSE_INIT_FLAG_CASE(HAS_IOCTL_DIR);
|
|
FUSE_INIT_FLAG_CASE(AUTO_INVAL_DATA);
|
|
FUSE_INIT_FLAG_CASE(DO_READDIRPLUS);
|
|
FUSE_INIT_FLAG_CASE(READDIRPLUS_AUTO);
|
|
FUSE_INIT_FLAG_CASE(ASYNC_DIO);
|
|
FUSE_INIT_FLAG_CASE(WRITEBACK_CACHE);
|
|
FUSE_INIT_FLAG_CASE(NO_OPEN_SUPPORT);
|
|
FUSE_INIT_FLAG_CASE(PARALLEL_DIROPS);
|
|
FUSE_INIT_FLAG_CASE(HANDLE_KILLPRIV);
|
|
FUSE_INIT_FLAG_CASE(POSIX_ACL);
|
|
FUSE_INIT_FLAG_CASE(ABORT_ERROR);
|
|
FUSE_INIT_FLAG_CASE(MAX_PAGES);
|
|
FUSE_INIT_FLAG_CASE(CACHE_SYMLINKS);
|
|
FUSE_INIT_FLAG_CASE(NO_OPENDIR_SUPPORT);
|
|
FUSE_INIT_FLAG_CASE(EXPLICIT_INVAL_DATA);
|
|
FUSE_INIT_FLAG_CASE(MAP_ALIGNMENT);
|
|
FUSE_INIT_FLAG_CASE(SUBMOUNTS);
|
|
FUSE_INIT_FLAG_CASE(HANDLE_KILLPRIV_V2);
|
|
FUSE_INIT_FLAG_CASE(SETXATTR_EXT);
|
|
FUSE_INIT_FLAG_CASE(INIT_EXT);
|
|
FUSE_INIT_FLAG_CASE(INIT_RESERVED);
|
|
FUSE_INIT_FLAG_CASE(SECURITY_CTX);
|
|
FUSE_INIT_FLAG_CASE(HAS_INODE_DAX);
|
|
FUSE_INIT_FLAG_CASE(CREATE_SUPP_GROUP);
|
|
FUSE_INIT_FLAG_CASE(HAS_EXPIRE_ONLY);
|
|
FUSE_INIT_FLAG_CASE(DIRECT_IO_ALLOW_MMAP);
|
|
FUSE_INIT_FLAG_CASE(PASSTHROUGH);
|
|
FUSE_INIT_FLAG_CASE(NO_EXPORT_SUPPORT);
|
|
FUSE_INIT_FLAG_CASE(HAS_RESEND);
|
|
FUSE_INIT_FLAG_CASE(ALLOW_IDMAP);
|
|
FUSE_INIT_FLAG_CASE(OVER_IO_URING);
|
|
FUSE_INIT_FLAG_CASE(REQUEST_TIMEOUT);
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
#undef FUSE_INIT_FLAG_CASE
|
|
|
|
static
|
|
const
|
|
char*
|
|
_fuse_flag_to_str(const uint64_t offset_)
|
|
{
|
|
return ::_fuse_init_flag_name(1ULL << offset_);
|
|
}
|
|
|
|
std::string
|
|
fuse_debug_init_flag_name(const uint64_t flag_)
|
|
{
|
|
const char *s = ::_fuse_init_flag_name(flag_);
|
|
return s ? s : "unknown";
|
|
}
|
|
|
|
static
|
|
std::string
|
|
_open_flags_str(const uint32_t flags_)
|
|
{
|
|
std::string buf;
|
|
|
|
buf += _open_accmode_to_str(flags_);
|
|
for(size_t i = 0; i < (sizeof(flags_) * 8); i++)
|
|
{
|
|
const char *str;
|
|
|
|
if(!(flags_ & (1 << i)))
|
|
continue;
|
|
|
|
str = _open_flag_to_str(i);
|
|
if(str == NULL)
|
|
continue;
|
|
|
|
buf += '|';
|
|
buf += str;
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
|
|
#define FOPEN_FLAG_CASE(X) case FOPEN_##X: return #X
|
|
|
|
static
|
|
const
|
|
char*
|
|
_fuse_fopen_flag_to_str(const uint32_t offset_)
|
|
{
|
|
switch(1 << offset_)
|
|
{
|
|
FOPEN_FLAG_CASE(DIRECT_IO);
|
|
FOPEN_FLAG_CASE(KEEP_CACHE);
|
|
FOPEN_FLAG_CASE(NONSEEKABLE);
|
|
FOPEN_FLAG_CASE(CACHE_DIR);
|
|
FOPEN_FLAG_CASE(STREAM);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
#undef FOPEN_FLAG_CASE
|
|
|
|
static
|
|
std::string
|
|
_fopen_flags_str(const uint32_t flags_)
|
|
{
|
|
std::string buf;
|
|
|
|
for(size_t i = 0; i < (sizeof(flags_) * 8); i++)
|
|
{
|
|
const char *str;
|
|
|
|
if(!(flags_ & (1 << i)))
|
|
continue;
|
|
|
|
str = _fuse_fopen_flag_to_str(i);
|
|
if(str == NULL)
|
|
continue;
|
|
|
|
if(!buf.empty())
|
|
buf += '|';
|
|
buf += str;
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
|
|
static
|
|
std::string
|
|
_write_flags_str(const uint32_t flags_)
|
|
{
|
|
std::string buf;
|
|
|
|
for(size_t i = 0; i < (sizeof(flags_) * 8); i++)
|
|
{
|
|
const char *str;
|
|
|
|
if(!(flags_ & (1 << i)))
|
|
continue;
|
|
|
|
str = _fuse_write_flag_to_str(i);
|
|
if(str == NULL)
|
|
continue;
|
|
|
|
if(!buf.empty())
|
|
buf += '|';
|
|
buf += str;
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
|
|
static
|
|
std::string
|
|
_fuse_init_flags_str(const uint64_t flags_)
|
|
{
|
|
std::string buf;
|
|
|
|
for(uint64_t i = 0; i < (sizeof(flags_)*8); i++)
|
|
{
|
|
const char *str;
|
|
|
|
if(!(flags_ & (1ULL << i)))
|
|
continue;
|
|
|
|
str = _fuse_flag_to_str(i);
|
|
if(str == NULL)
|
|
continue;
|
|
|
|
if(!buf.empty())
|
|
buf += '|';
|
|
buf += str;
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
|
|
static
|
|
std::string
|
|
_xattr_value_to_printable(const char *data_,
|
|
uint32_t size_)
|
|
{
|
|
bool is_printable = true;
|
|
|
|
for(uint32_t i = 0; i < size_; i++)
|
|
{
|
|
unsigned char c = (unsigned char)data_[i];
|
|
if(c < 0x20 || c > 0x7E)
|
|
{
|
|
is_printable = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(is_printable)
|
|
return _quoted(data_,size_);
|
|
|
|
std::string hex;
|
|
hex += '"';
|
|
for(uint32_t i = 0; i < size_; i++)
|
|
{
|
|
if(i > 0)
|
|
hex += ' ';
|
|
hex += fmt::format("{:02X}",(unsigned char)data_[i]);
|
|
}
|
|
hex += '"';
|
|
|
|
return hex;
|
|
}
|
|
|
|
void
|
|
fuse_debug_open_out(const uint64_t unique_,
|
|
const struct fuse_open_out *arg_,
|
|
const uint64_t argsize_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
fmt::print(output.get(),
|
|
"ts={}"
|
|
" dir=OUT"
|
|
" unique=0x{:016X}"
|
|
" error=0"
|
|
" len={}"
|
|
" fh=0x{:08X}"
|
|
" open_flags=0x{:04X}"
|
|
" open_flags_str=\"{}\""
|
|
"\n",
|
|
_timestamp_ns(),
|
|
unique_,
|
|
sizeof(struct fuse_out_header) + argsize_,
|
|
arg_->fh,
|
|
arg_->open_flags,
|
|
_fopen_flags_str(arg_->open_flags));
|
|
}
|
|
|
|
static
|
|
void
|
|
_debug_fuse_lookup(const void *arg_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
const char *name = (const char*)arg_;
|
|
|
|
fmt::print(output.get(),
|
|
"name={}\n",
|
|
::_quoted(name));
|
|
}
|
|
|
|
static
|
|
void
|
|
_debug_fuse_getattr_in(const void *arg_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
const struct fuse_getattr_in *arg = (const fuse_getattr_in*)arg_;
|
|
|
|
fmt::print(output.get(),
|
|
"getattr_flags=0x{:08X}"
|
|
" fh=0x{:08X}"
|
|
"\n",
|
|
arg->getattr_flags,
|
|
arg->fh);
|
|
}
|
|
|
|
static
|
|
void
|
|
_debug_fuse_setattr_in(const void *arg_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
const struct fuse_setattr_in *arg = (const fuse_setattr_in*)arg_;
|
|
|
|
fmt::print(output.get(),
|
|
"valid={}"
|
|
" fh=0x{:08X}"
|
|
" size={}"
|
|
" lock_owner={}"
|
|
" atime={}"
|
|
" atimensec={}"
|
|
" mtime={}"
|
|
" mtimensec={}"
|
|
" ctime={}"
|
|
" ctimensec={}"
|
|
" mode={:o}"
|
|
" uid={}"
|
|
" gid={}"
|
|
"\n",
|
|
arg->valid,
|
|
arg->fh,
|
|
arg->size,
|
|
arg->lock_owner,
|
|
arg->atime,
|
|
arg->atimensec,
|
|
arg->mtime,
|
|
arg->mtimensec,
|
|
arg->ctime,
|
|
arg->ctimensec,
|
|
arg->mode,
|
|
arg->uid,
|
|
arg->gid);
|
|
}
|
|
|
|
static
|
|
void
|
|
_debug_fuse_access_in(const void *arg_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
const struct fuse_access_in *arg = (const fuse_access_in*)arg_;
|
|
|
|
fmt::print(output.get(),
|
|
"mask=0x{:08X}"
|
|
"\n",
|
|
arg->mask);
|
|
}
|
|
|
|
static
|
|
void
|
|
_debug_fuse_mknod_in(const void *arg_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
const struct fuse_mknod_in *arg = (const fuse_mknod_in*)arg_;
|
|
|
|
fmt::print(output.get(),
|
|
"mode={:o}"
|
|
" rdev=0x{:08X}"
|
|
" umask={:o}"
|
|
" name={}"
|
|
"\n",
|
|
arg->mode,
|
|
arg->rdev,
|
|
arg->umask,
|
|
_quoted(PARAM(arg)));
|
|
}
|
|
|
|
static
|
|
void
|
|
_debug_fuse_mkdir_in(const void *arg_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
const struct fuse_mkdir_in *arg = (const fuse_mkdir_in*)arg_;
|
|
|
|
fmt::print(output.get(),
|
|
"mode={:o}"
|
|
" umask={:o}"
|
|
" name={}"
|
|
"\n",
|
|
arg->mode,
|
|
arg->umask,
|
|
_quoted(PARAM(arg)));
|
|
}
|
|
|
|
static
|
|
void
|
|
_debug_fuse_unlink(const void *arg_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
const char *name = (const char*)arg_;
|
|
|
|
fmt::print(output.get(),
|
|
"name={}"
|
|
"\n",
|
|
::_quoted(name));
|
|
}
|
|
|
|
static
|
|
void
|
|
_debug_fuse_rmdir(const void *arg_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
const char *name = (const char*)arg_;
|
|
|
|
fmt::print(output.get(),
|
|
"name={}"
|
|
"\n",
|
|
::_quoted(name));
|
|
}
|
|
|
|
static
|
|
void
|
|
_debug_fuse_symlink(const void *arg_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
const char *name;
|
|
const char *linkname;
|
|
|
|
name = (const char*)arg_;
|
|
linkname = (name + (strlen(name) + 1));
|
|
|
|
fmt::print(output.get(),
|
|
"name={}"
|
|
" linkname={}"
|
|
"\n",
|
|
_quoted(name),
|
|
_quoted(linkname));
|
|
}
|
|
|
|
static
|
|
void
|
|
_debug_fuse_rename_in(const void *arg_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
const char *oldname;
|
|
const char *newname;
|
|
const struct fuse_rename_in *arg = (const fuse_rename_in*)arg_;
|
|
|
|
oldname = PARAM(arg);
|
|
newname = (oldname + strlen(oldname) + 1);
|
|
|
|
fmt::print(output.get(),
|
|
"oldname={}"
|
|
" newdir={}"
|
|
" newname={}"
|
|
"\n",
|
|
_quoted(oldname),
|
|
arg->newdir,
|
|
_quoted(newname));
|
|
}
|
|
|
|
static
|
|
void
|
|
_debug_fuse_link_in(const void *arg_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
const char *name;
|
|
const struct fuse_link_in *arg = (const fuse_link_in*)arg_;
|
|
|
|
name = PARAM(arg);
|
|
|
|
fmt::print(output.get(),
|
|
"oldnodeid={}"
|
|
" name={}"
|
|
"\n",
|
|
arg->oldnodeid,
|
|
::_quoted(name));
|
|
}
|
|
|
|
static
|
|
void
|
|
_debug_fuse_create_in(const void *arg_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
const char *name;
|
|
const struct fuse_create_in *arg = (const fuse_create_in*)arg_;
|
|
|
|
name = PARAM(arg);
|
|
|
|
fmt::print(output.get(),
|
|
"mode={:o}"
|
|
" umask={:o}"
|
|
" name={}"
|
|
" flags=0x{:X}"
|
|
" flags_str=\"{}\""
|
|
"\n",
|
|
arg->mode,
|
|
arg->umask,
|
|
_quoted(name),
|
|
arg->flags,
|
|
_open_flags_str(arg->flags));
|
|
}
|
|
|
|
static
|
|
void
|
|
_debug_fuse_open_in(const void *arg_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
const struct fuse_open_in *arg = (const fuse_open_in*)arg_;
|
|
|
|
fmt::print(output.get(),
|
|
"flags=0x{:08X}"
|
|
" flags_str=\"{}\""
|
|
"\n",
|
|
arg->flags,
|
|
_open_flags_str(arg->flags));
|
|
}
|
|
|
|
static
|
|
void
|
|
_debug_fuse_read_in(const void *arg_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
const struct fuse_read_in *arg = (const fuse_read_in*)arg_;
|
|
|
|
fmt::print(output.get(),
|
|
"fh=0x{:08X}"
|
|
" offset={}"
|
|
" size={}"
|
|
" read_flags=0x{:X}"
|
|
" lock_owner=0x{:08X}"
|
|
" flags=0x{:X}"
|
|
" flags_str=\"{}\""
|
|
"\n",
|
|
arg->fh,
|
|
arg->offset,
|
|
arg->size,
|
|
arg->read_flags,
|
|
arg->lock_owner,
|
|
arg->flags,
|
|
_open_flags_str(arg->flags));
|
|
}
|
|
|
|
static
|
|
void
|
|
_debug_fuse_write_in(const void *arg_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
const struct fuse_write_in *arg = (const fuse_write_in*)arg_;
|
|
|
|
fmt::print(output.get(),
|
|
"fh=0x{:08X}"
|
|
" offset={}"
|
|
" size={}"
|
|
" lock_owner=0x{:08X}"
|
|
" flags=0x{:X}"
|
|
" flags_str=\"{}\""
|
|
" write_flags=0x{:X}"
|
|
" write_flags_str=\"{}\""
|
|
"\n",
|
|
arg->fh,
|
|
arg->offset,
|
|
arg->size,
|
|
arg->lock_owner,
|
|
arg->flags,
|
|
_open_flags_str(arg->flags),
|
|
arg->write_flags,
|
|
_write_flags_str(arg->write_flags));
|
|
}
|
|
|
|
static
|
|
void
|
|
_debug_fuse_flush_in(const void *arg_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
const struct fuse_flush_in *arg = (const fuse_flush_in*)arg_;
|
|
|
|
fmt::print(output.get(),
|
|
"fh=0x{:08X}"
|
|
" lock_owner=0x{:08X}"
|
|
"\n",
|
|
arg->fh,
|
|
arg->lock_owner);
|
|
}
|
|
|
|
static
|
|
void
|
|
_debug_fuse_release_in(const void *arg_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
const struct fuse_release_in *arg = (const fuse_release_in*)arg_;
|
|
|
|
fmt::print(output.get(),
|
|
"fh=0x{:08X}"
|
|
" release_flags=0x{:X}"
|
|
" lock_owner=0x{:08X}"
|
|
" flags=0x{:X}"
|
|
" flags_str=\"{}\""
|
|
"\n",
|
|
arg->fh,
|
|
arg->release_flags,
|
|
arg->lock_owner,
|
|
arg->flags,
|
|
_open_flags_str(arg->flags));
|
|
}
|
|
|
|
static
|
|
void
|
|
_debug_fuse_fsync_in(const void *arg_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
const struct fuse_fsync_in *arg = (const fuse_fsync_in*)arg_;
|
|
|
|
fmt::print(output.get(),
|
|
"fh=0x{:08X}"
|
|
" fsync_flags=0x{:X}"
|
|
"\n",
|
|
arg->fh,
|
|
arg->fsync_flags);
|
|
}
|
|
|
|
static
|
|
void
|
|
_debug_fuse_setxattr_in(const void *arg_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
const char *name;
|
|
const char *value;
|
|
const struct fuse_setxattr_in *arg = (const fuse_setxattr_in*)arg_;
|
|
|
|
name = PARAM(arg);
|
|
value = (name + strlen(name) + 1);
|
|
|
|
fmt::print(output.get(),
|
|
"size={}"
|
|
" flags=0x{:X}"
|
|
" name={}"
|
|
" value={}"
|
|
"\n",
|
|
arg->size,
|
|
arg->flags,
|
|
_quoted(name),
|
|
_xattr_value_to_printable(value,arg->size));
|
|
}
|
|
|
|
static
|
|
void
|
|
_debug_fuse_getxattr_in(const void *arg_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
const char *name;
|
|
const struct fuse_getxattr_in *arg = (const fuse_getxattr_in*)arg_;
|
|
|
|
name = PARAM(arg);
|
|
|
|
fmt::print(output.get(),
|
|
"size={}"
|
|
" name={}"
|
|
"\n",
|
|
arg->size,
|
|
::_quoted(name));
|
|
}
|
|
|
|
static
|
|
void
|
|
_debug_fuse_listxattr(const void *arg_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
const struct fuse_getxattr_in *arg = (const fuse_getxattr_in*)arg_;
|
|
|
|
fmt::print(output.get(),
|
|
"size={}"
|
|
"\n",
|
|
arg->size);
|
|
}
|
|
|
|
static
|
|
void
|
|
_debug_fuse_removexattr(const void *arg_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
const char *name = (const char*)arg_;
|
|
|
|
fmt::print(output.get(),
|
|
"name={}"
|
|
"\n",
|
|
::_quoted(name));
|
|
}
|
|
|
|
static
|
|
void
|
|
_debug_fuse_fallocate_in(const void *arg_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
const struct fuse_fallocate_in *arg = (const fuse_fallocate_in*)arg_;
|
|
|
|
fmt::print(output.get(),
|
|
"fh=0x{:08X}"
|
|
" offset={}"
|
|
" length={}"
|
|
" mode={:o}"
|
|
"\n",
|
|
arg->fh,
|
|
arg->offset,
|
|
arg->length,
|
|
arg->mode);
|
|
}
|
|
|
|
static
|
|
void
|
|
_debug_fuse_forget_in(const void *arg_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
const struct fuse_forget_in *arg = (const fuse_forget_in*)arg_;
|
|
|
|
fmt::print(output.get(),
|
|
"nlookup={}"
|
|
"\n",
|
|
arg->nlookup);
|
|
}
|
|
|
|
static
|
|
void
|
|
_debug_fuse_batch_forget_in(const void *arg_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
const struct fuse_batch_forget_in *arg = (const fuse_batch_forget_in*)arg_;
|
|
const struct fuse_forget_one *items = (const fuse_forget_one*)PARAM(arg);
|
|
|
|
fmt::print(output.get(),
|
|
"count={}",
|
|
arg->count);
|
|
for(uint32_t i = 0; i < arg->count; i++)
|
|
{
|
|
fmt::print(output.get(),
|
|
" item.{}={{nodeid={},nlookup={}}}",
|
|
i,
|
|
items[i].nodeid,
|
|
items[i].nlookup);
|
|
}
|
|
fmt::print(output.get(),"\n");
|
|
}
|
|
|
|
static
|
|
void
|
|
_debug_fuse_lk_in(const void *arg_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
const struct fuse_lk_in *arg = (const fuse_lk_in*)arg_;
|
|
|
|
fmt::print(output.get(),
|
|
"fh=0x{:08X}"
|
|
" owner=0x{:016X}"
|
|
" lk_start={}"
|
|
" lk_end={}"
|
|
" lk_type={}"
|
|
" lk_pid={}"
|
|
" lk_flags=0x{:X}"
|
|
"\n",
|
|
arg->fh,
|
|
arg->owner,
|
|
arg->lk.start,
|
|
arg->lk.end,
|
|
arg->lk.type,
|
|
arg->lk.pid,
|
|
arg->lk_flags);
|
|
}
|
|
|
|
static
|
|
void
|
|
_debug_fuse_bmap_in(const void *arg_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
const struct fuse_bmap_in *arg = (const fuse_bmap_in*)arg_;
|
|
|
|
fmt::print(output.get(),
|
|
"block={}"
|
|
" blocksize={}"
|
|
"\n",
|
|
arg->block,
|
|
arg->blocksize);
|
|
}
|
|
|
|
static
|
|
void
|
|
_debug_fuse_ioctl_in(const void *arg_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
const struct fuse_ioctl_in *arg = (const fuse_ioctl_in*)arg_;
|
|
|
|
fmt::print(output.get(),
|
|
"fh=0x{:08X}"
|
|
" flags=0x{:X}"
|
|
" cmd=0x{:X}"
|
|
" arg=0x{:016X}"
|
|
" in_size={}"
|
|
" out_size={}"
|
|
"\n",
|
|
arg->fh,
|
|
arg->flags,
|
|
arg->cmd,
|
|
arg->arg,
|
|
arg->in_size,
|
|
arg->out_size);
|
|
}
|
|
|
|
static
|
|
void
|
|
_debug_fuse_poll_in(const void *arg_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
const struct fuse_poll_in *arg = (const fuse_poll_in*)arg_;
|
|
|
|
fmt::print(output.get(),
|
|
"fh=0x{:08X}"
|
|
" kh=0x{:016X}"
|
|
" flags=0x{:X}"
|
|
" events=0x{:X}"
|
|
"\n",
|
|
arg->fh,
|
|
arg->kh,
|
|
arg->flags,
|
|
arg->events);
|
|
}
|
|
|
|
static
|
|
void
|
|
_debug_fuse_rename2_in(const void *arg_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
const char *oldname;
|
|
const char *newname;
|
|
const struct fuse_rename2_in *arg = (const fuse_rename2_in*)arg_;
|
|
|
|
oldname = PARAM(arg);
|
|
newname = (oldname + strlen(oldname) + 1);
|
|
|
|
fmt::print(output.get(),
|
|
"oldname={}"
|
|
" newdir={}"
|
|
" newname={}"
|
|
" flags=0x{:X}"
|
|
"\n",
|
|
_quoted(oldname),
|
|
arg->newdir,
|
|
_quoted(newname),
|
|
arg->flags);
|
|
}
|
|
|
|
static
|
|
void
|
|
_debug_fuse_lseek_in(const void *arg_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
const struct fuse_lseek_in *arg = (const fuse_lseek_in*)arg_;
|
|
|
|
fmt::print(output.get(),
|
|
"fh=0x{:08X}"
|
|
" offset={}"
|
|
" whence={}"
|
|
"\n",
|
|
arg->fh,
|
|
arg->offset,
|
|
arg->whence);
|
|
}
|
|
|
|
static
|
|
void
|
|
_debug_fuse_copy_file_range_in(const void *arg_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
const struct fuse_copy_file_range_in *arg = (const fuse_copy_file_range_in*)arg_;
|
|
|
|
fmt::print(output.get(),
|
|
"fh_in=0x{:08X}"
|
|
" off_in={}"
|
|
" nodeid_out={}"
|
|
" fh_out=0x{:08X}"
|
|
" off_out={}"
|
|
" len={}"
|
|
" flags=0x{:X}"
|
|
"\n",
|
|
arg->fh_in,
|
|
arg->off_in,
|
|
arg->nodeid_out,
|
|
arg->fh_out,
|
|
arg->off_out,
|
|
arg->len,
|
|
arg->flags);
|
|
}
|
|
|
|
static
|
|
void
|
|
_debug_fuse_statx_in(const void *arg_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
const struct fuse_statx_in *arg = (const fuse_statx_in*)arg_;
|
|
|
|
fmt::print(output.get(),
|
|
"getattr_flags=0x{:08X}"
|
|
" fh=0x{:08X}"
|
|
" sx_flags=0x{:X}"
|
|
" sx_mask=0x{:X}"
|
|
"\n",
|
|
arg->getattr_flags,
|
|
arg->fh,
|
|
arg->sx_flags,
|
|
arg->sx_mask);
|
|
}
|
|
|
|
static
|
|
void
|
|
_debug_init_in(const struct fuse_init_in *arg_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
uint64_t flags;
|
|
|
|
flags = (((uint64_t)arg_->flags) | ((uint64_t)arg_->flags2) << 32);
|
|
fmt::print(output.get(),
|
|
"major={}"
|
|
" minor={}"
|
|
" max_readahead={}"
|
|
" flags=0x{:016X}"
|
|
" flags_str=\"{}\""
|
|
"\n",
|
|
arg_->major,
|
|
arg_->minor,
|
|
arg_->max_readahead,
|
|
flags,
|
|
_fuse_init_flags_str(flags));
|
|
}
|
|
|
|
void
|
|
fuse_syslog_fuse_init_in(const struct fuse_init_in *arg_)
|
|
{
|
|
uint64_t flags;
|
|
std::string output;
|
|
|
|
flags = (((uint64_t)arg_->flags) | ((uint64_t)arg_->flags2) << 32);
|
|
output = fmt::format("fuse_init_in:"
|
|
" major={};"
|
|
" minor={};"
|
|
" flags=(",
|
|
arg_->major,
|
|
arg_->minor);
|
|
|
|
for(uint64_t i = 0; i < (sizeof(flags)*8); i++)
|
|
{
|
|
if(!(flags & (1ULL << i)))
|
|
continue;
|
|
|
|
output += fuse_debug_init_flag_name(1ULL << i);
|
|
|
|
output += ",";
|
|
}
|
|
|
|
output.pop_back();
|
|
output += ");";
|
|
|
|
SysLog::info(output);
|
|
}
|
|
|
|
void
|
|
fuse_syslog_fuse_init_out(const struct fuse_init_out *arg_)
|
|
{
|
|
uint64_t flags;
|
|
std::string output;
|
|
|
|
flags = (((uint64_t)arg_->flags) | ((uint64_t)arg_->flags2) << 32);
|
|
output = fmt::format("fuse_init_out:"
|
|
" major={};"
|
|
" minor={};"
|
|
" max_readahead={};"
|
|
" max_background={};"
|
|
" congestion_threshold={};"
|
|
" max_write={};"
|
|
" time_gran={};"
|
|
" max_pages={};"
|
|
" map_alignment={};"
|
|
" max_stack_depth={};"
|
|
" request_timeout={};"
|
|
" flags=(",
|
|
arg_->major,
|
|
arg_->minor,
|
|
arg_->max_readahead,
|
|
arg_->max_background,
|
|
arg_->congestion_threshold,
|
|
arg_->max_write,
|
|
arg_->time_gran,
|
|
arg_->max_pages,
|
|
arg_->map_alignment,
|
|
arg_->max_stack_depth,
|
|
arg_->request_timeout);
|
|
|
|
for(uint64_t i = 0; i < (sizeof(flags)*8); i++)
|
|
{
|
|
if(!(flags & (1ULL << i)))
|
|
continue;
|
|
|
|
output += fuse_debug_init_flag_name(1ULL << i);
|
|
|
|
output += ",";
|
|
}
|
|
|
|
output.pop_back();
|
|
output += ");";
|
|
|
|
SysLog::info(output);
|
|
}
|
|
|
|
|
|
void
|
|
fuse_debug_init_out(const uint64_t unique_,
|
|
const struct fuse_init_out *arg_,
|
|
const uint64_t argsize_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
uint64_t flags;
|
|
|
|
flags = (((uint64_t)arg_->flags) | ((uint64_t)arg_->flags2) << 32);
|
|
fmt::print(output.get(),
|
|
"ts={}"
|
|
" dir=OUT"
|
|
" unique=0x{:016X}"
|
|
" error=0"
|
|
" len={}"
|
|
" major={}"
|
|
" minor={}"
|
|
" max_readahead={}"
|
|
" flags=0x{:016X}"
|
|
" flags_str=\"{}\""
|
|
" max_background={}"
|
|
" congestion_threshold={}"
|
|
" max_write={}"
|
|
" time_gran={}"
|
|
" max_pages={}"
|
|
" map_alignment={}"
|
|
" request_timeout={}"
|
|
"\n",
|
|
_timestamp_ns(),
|
|
unique_,
|
|
sizeof(struct fuse_out_header) + argsize_,
|
|
arg_->major,
|
|
arg_->minor,
|
|
arg_->max_readahead,
|
|
flags,
|
|
_fuse_init_flags_str(flags),
|
|
arg_->max_background,
|
|
arg_->congestion_threshold,
|
|
arg_->max_write,
|
|
arg_->time_gran,
|
|
arg_->max_pages,
|
|
arg_->map_alignment,
|
|
arg_->request_timeout);
|
|
}
|
|
|
|
static
|
|
void
|
|
_debug_fuse_attr(const struct fuse_attr *attr_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
fmt::print(output.get(),
|
|
"ino=0x{:016X}"
|
|
" size={}"
|
|
" blocks={}"
|
|
" atime={}"
|
|
" atimensec={}"
|
|
" mtime={}"
|
|
" mtimensec={}"
|
|
" ctime={}"
|
|
" ctimensec={}"
|
|
" mode={:o}"
|
|
" nlink={}"
|
|
" uid={}"
|
|
" gid={}"
|
|
" rdev={}"
|
|
" blksize={}",
|
|
attr_->ino,
|
|
attr_->size,
|
|
attr_->blocks,
|
|
attr_->atime,
|
|
attr_->atimensec,
|
|
attr_->mtime,
|
|
attr_->mtimensec,
|
|
attr_->ctime,
|
|
attr_->ctimensec,
|
|
attr_->mode,
|
|
attr_->nlink,
|
|
attr_->uid,
|
|
attr_->gid,
|
|
attr_->rdev,
|
|
attr_->blksize);
|
|
}
|
|
|
|
static
|
|
void
|
|
_debug_fuse_entry(const struct fuse_entry_out *entry_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
fmt::print(output.get(),
|
|
"nodeid=0x{:016X}"
|
|
" generation=0x{:016X}"
|
|
" entry_valid={}"
|
|
" entry_valid_nsec={}"
|
|
" attr_valid={}"
|
|
" attr_valid_nsec={}"
|
|
" ",
|
|
entry_->nodeid,
|
|
entry_->generation,
|
|
entry_->entry_valid,
|
|
entry_->entry_valid_nsec,
|
|
entry_->attr_valid,
|
|
entry_->attr_valid_nsec);
|
|
_debug_fuse_attr(&entry_->attr);
|
|
}
|
|
|
|
void
|
|
fuse_debug_entry_out(const uint64_t unique_,
|
|
const struct fuse_entry_out *arg_,
|
|
const uint64_t argsize_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
fmt::print(output.get(),
|
|
"ts={}"
|
|
" dir=OUT"
|
|
" unique=0x{:016X}"
|
|
" error=0"
|
|
" len={}"
|
|
" ",
|
|
_timestamp_ns(),
|
|
unique_,
|
|
sizeof(struct fuse_out_header) + argsize_);
|
|
_debug_fuse_entry(arg_);
|
|
fmt::print(output.get(),"\n");
|
|
}
|
|
|
|
void
|
|
fuse_debug_attr_out(const uint64_t unique_,
|
|
const struct fuse_attr_out *arg_,
|
|
const uint64_t argsize_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
fmt::print(output.get(),
|
|
"ts={}"
|
|
" dir=OUT"
|
|
" unique=0x{:016X}"
|
|
" error=0"
|
|
" len={}"
|
|
" attr_valid={}"
|
|
" attr_valid_nsec={}"
|
|
" ino=0x{:016X}"
|
|
" size={}"
|
|
" blocks={}"
|
|
" atime={}"
|
|
" atimensec={}"
|
|
" mtime={}"
|
|
" mtimensec={}"
|
|
" ctime={}"
|
|
" ctimensec={}"
|
|
" mode={:o}"
|
|
" nlink={}"
|
|
" uid={}"
|
|
" gid={}"
|
|
" rdev={}"
|
|
" blksize={}"
|
|
"\n",
|
|
_timestamp_ns(),
|
|
unique_,
|
|
sizeof(struct fuse_out_header) + argsize_,
|
|
arg_->attr_valid,
|
|
arg_->attr_valid_nsec,
|
|
arg_->attr.ino,
|
|
arg_->attr.size,
|
|
arg_->attr.blocks,
|
|
arg_->attr.atime,
|
|
arg_->attr.atimensec,
|
|
arg_->attr.mtime,
|
|
arg_->attr.mtimensec,
|
|
arg_->attr.ctime,
|
|
arg_->attr.ctimensec,
|
|
arg_->attr.mode,
|
|
arg_->attr.nlink,
|
|
arg_->attr.uid,
|
|
arg_->attr.gid,
|
|
arg_->attr.rdev,
|
|
arg_->attr.blksize);
|
|
}
|
|
|
|
static
|
|
void
|
|
_debug_fuse_interrupt_in(const void *arg_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
const struct fuse_interrupt_in *arg = (const fuse_interrupt_in*)arg_;
|
|
|
|
fmt::print(output.get(),
|
|
"target_unique=0x{:016X}"
|
|
"\n",
|
|
arg->unique);
|
|
}
|
|
|
|
static
|
|
const
|
|
char*
|
|
_opcode_name(enum fuse_opcode op_)
|
|
{
|
|
static const char *names[] =
|
|
{
|
|
"RESERVED",
|
|
"LOOKUP",
|
|
"FORGET",
|
|
"GETATTR",
|
|
"SETATTR",
|
|
"READLINK",
|
|
"SYMLINK",
|
|
"RESERVED",
|
|
"MKNOD",
|
|
"MKDIR",
|
|
"UNLINK",
|
|
"RMDIR",
|
|
"RENAME",
|
|
"LINK",
|
|
"OPEN",
|
|
"READ",
|
|
"WRITE",
|
|
"STATFS",
|
|
"RELEASE",
|
|
"RESERVED",
|
|
"FSYNC",
|
|
"SETXATTR",
|
|
"GETXATTR",
|
|
"LISTXATTR",
|
|
"REMOVEXATTR",
|
|
"FLUSH",
|
|
"INIT",
|
|
"OPENDIR",
|
|
"READDIR",
|
|
"RELEASEDIR",
|
|
"FSYNCDIR",
|
|
"GETLK",
|
|
"SETLK",
|
|
"SETLKW",
|
|
"ACCESS",
|
|
"CREATE",
|
|
"INTERRUPT",
|
|
"BMAP",
|
|
"DESTROY",
|
|
"IOCTL",
|
|
"POLL",
|
|
"NOTIFY_REPLY",
|
|
"BATCH_FORGET",
|
|
"FALLOCATE",
|
|
"READDIRPLUS",
|
|
"RENAME2",
|
|
"LSEEK",
|
|
"COPY_FILE_RANGE",
|
|
"SETUPMAPPING",
|
|
"REMOVEMAPPING",
|
|
"SYNCFS",
|
|
"TMPFILE",
|
|
"STATX",
|
|
"COPY_FILE_RANGE_64"
|
|
};
|
|
|
|
if(op_ >= (sizeof(names) / sizeof(names[0])))
|
|
return "UNKNOWN";
|
|
|
|
return names[op_];
|
|
}
|
|
|
|
void
|
|
fuse_debug_in_header(const struct fuse_in_header *hdr_)
|
|
{
|
|
const void *arg = &hdr_[1];
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
flockfile(output.get());
|
|
|
|
fmt::print(output.get(),
|
|
"ts={}"
|
|
" dir=IN"
|
|
" unique=0x{:016X}"
|
|
" opcode={}"
|
|
" opcode_id={}"
|
|
" nodeid={}"
|
|
" uid={}"
|
|
" gid={}"
|
|
" pid={}"
|
|
" ",
|
|
_timestamp_ns(),
|
|
hdr_->unique,
|
|
_opcode_name((fuse_opcode)hdr_->opcode),
|
|
hdr_->opcode,
|
|
hdr_->nodeid,
|
|
hdr_->uid,
|
|
hdr_->gid,
|
|
hdr_->pid);
|
|
|
|
switch(hdr_->opcode)
|
|
{
|
|
case FUSE_LOOKUP:
|
|
_debug_fuse_lookup(arg);
|
|
break;
|
|
case FUSE_FORGET:
|
|
_debug_fuse_forget_in(arg);
|
|
break;
|
|
case FUSE_GETATTR:
|
|
_debug_fuse_getattr_in(arg);
|
|
break;
|
|
case FUSE_SETATTR:
|
|
_debug_fuse_setattr_in(arg);
|
|
break;
|
|
case FUSE_READLINK:
|
|
fmt::print(output.get(),"\n");
|
|
break;
|
|
case FUSE_SYMLINK:
|
|
_debug_fuse_symlink(arg);
|
|
break;
|
|
case FUSE_UNLINK:
|
|
_debug_fuse_unlink(arg);
|
|
break;
|
|
case FUSE_RMDIR:
|
|
_debug_fuse_rmdir(arg);
|
|
break;
|
|
case FUSE_MKNOD:
|
|
_debug_fuse_mknod_in(arg);
|
|
break;
|
|
case FUSE_MKDIR:
|
|
_debug_fuse_mkdir_in(arg);
|
|
break;
|
|
case FUSE_RENAME:
|
|
_debug_fuse_rename_in(arg);
|
|
break;
|
|
case FUSE_LINK:
|
|
_debug_fuse_link_in(arg);
|
|
break;
|
|
case FUSE_OPEN:
|
|
_debug_fuse_open_in(arg);
|
|
break;
|
|
case FUSE_READ:
|
|
_debug_fuse_read_in(arg);
|
|
break;
|
|
case FUSE_WRITE:
|
|
_debug_fuse_write_in(arg);
|
|
break;
|
|
case FUSE_STATFS:
|
|
fmt::print(output.get(),"\n");
|
|
break;
|
|
case FUSE_RELEASE:
|
|
_debug_fuse_release_in(arg);
|
|
break;
|
|
case FUSE_FSYNC:
|
|
_debug_fuse_fsync_in(arg);
|
|
break;
|
|
case FUSE_SETXATTR:
|
|
_debug_fuse_setxattr_in(arg);
|
|
break;
|
|
case FUSE_GETXATTR:
|
|
_debug_fuse_getxattr_in(arg);
|
|
break;
|
|
case FUSE_LISTXATTR:
|
|
_debug_fuse_listxattr(arg);
|
|
break;
|
|
case FUSE_REMOVEXATTR:
|
|
_debug_fuse_removexattr(arg);
|
|
break;
|
|
case FUSE_FLUSH:
|
|
_debug_fuse_flush_in(arg);
|
|
break;
|
|
case FUSE_OPENDIR:
|
|
_debug_fuse_open_in(arg);
|
|
break;
|
|
case FUSE_READDIR:
|
|
_debug_fuse_read_in(arg);
|
|
break;
|
|
case FUSE_RELEASEDIR:
|
|
_debug_fuse_release_in(arg);
|
|
break;
|
|
case FUSE_FSYNCDIR:
|
|
_debug_fuse_fsync_in(arg);
|
|
break;
|
|
case FUSE_GETLK:
|
|
_debug_fuse_lk_in(arg);
|
|
break;
|
|
case FUSE_SETLK:
|
|
_debug_fuse_lk_in(arg);
|
|
break;
|
|
case FUSE_SETLKW:
|
|
_debug_fuse_lk_in(arg);
|
|
break;
|
|
case FUSE_INTERRUPT:
|
|
_debug_fuse_interrupt_in(arg);
|
|
break;
|
|
case FUSE_BMAP:
|
|
_debug_fuse_bmap_in(arg);
|
|
break;
|
|
case FUSE_CREATE:
|
|
_debug_fuse_create_in(arg);
|
|
break;
|
|
case FUSE_IOCTL:
|
|
_debug_fuse_ioctl_in(arg);
|
|
break;
|
|
case FUSE_POLL:
|
|
_debug_fuse_poll_in(arg);
|
|
break;
|
|
case FUSE_BATCH_FORGET:
|
|
_debug_fuse_batch_forget_in(arg);
|
|
break;
|
|
case FUSE_FALLOCATE:
|
|
_debug_fuse_fallocate_in(arg);
|
|
break;
|
|
case FUSE_READDIRPLUS:
|
|
_debug_fuse_read_in(arg);
|
|
break;
|
|
case FUSE_RENAME2:
|
|
_debug_fuse_rename2_in(arg);
|
|
break;
|
|
case FUSE_LSEEK:
|
|
_debug_fuse_lseek_in(arg);
|
|
break;
|
|
case FUSE_COPY_FILE_RANGE:
|
|
case FUSE_COPY_FILE_RANGE_64:
|
|
_debug_fuse_copy_file_range_in(arg);
|
|
break;
|
|
case FUSE_TMPFILE:
|
|
_debug_fuse_create_in(arg);
|
|
break;
|
|
case FUSE_STATX:
|
|
_debug_fuse_statx_in(arg);
|
|
break;
|
|
case FUSE_ACCESS:
|
|
_debug_fuse_access_in(arg);
|
|
break;
|
|
case FUSE_INIT:
|
|
_debug_init_in((const fuse_init_in*)arg);
|
|
break;
|
|
default:
|
|
fmt::print(output.get(),"unknown_opcode={}\n",hdr_->opcode);
|
|
break;
|
|
}
|
|
|
|
funlockfile(output.get());
|
|
}
|
|
|
|
void
|
|
fuse_debug_out_header(const struct fuse_out_header *hdr_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
char strerror_buf[STRERR_BUF_SIZE];
|
|
|
|
fmt::print(output.get(),
|
|
"ts={}"
|
|
" dir=OUT"
|
|
" unique=0x{:016X}"
|
|
" error={}"
|
|
" error_str=\"{}\""
|
|
" len={}"
|
|
"\n",
|
|
_timestamp_ns(),
|
|
hdr_->unique,
|
|
hdr_->error,
|
|
strerror_r(-hdr_->error,strerror_buf,sizeof(strerror_buf)),
|
|
hdr_->len);
|
|
}
|
|
|
|
void
|
|
fuse_debug_entry_open_out(const uint64_t unique_,
|
|
const struct fuse_entry_out *entry_,
|
|
const struct fuse_open_out *open_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
fmt::print(output.get(),
|
|
"ts={}"
|
|
" dir=OUT"
|
|
" unique=0x{:016X}"
|
|
" error=0"
|
|
" len={}"
|
|
" ",
|
|
_timestamp_ns(),
|
|
unique_,
|
|
sizeof(struct fuse_entry_out) + sizeof(struct fuse_open_out));
|
|
_debug_fuse_entry(entry_);
|
|
fmt::print(output.get(),
|
|
" fh=0x{:08X}"
|
|
" open_flags=0x{:04X}"
|
|
" open_flags_str=\"{}\""
|
|
"\n",
|
|
open_->fh,
|
|
open_->open_flags,
|
|
_fopen_flags_str(open_->open_flags));
|
|
}
|
|
|
|
void
|
|
fuse_debug_readlink(const uint64_t unique_,
|
|
const char *linkname_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
fmt::print(output.get(),
|
|
"ts={}"
|
|
" dir=OUT"
|
|
" unique=0x{:016X}"
|
|
" error=0"
|
|
" len={}"
|
|
" linkname={}"
|
|
"\n",
|
|
_timestamp_ns(),
|
|
unique_,
|
|
(sizeof(struct fuse_out_header) + strlen(linkname_)),
|
|
_quoted(linkname_));
|
|
}
|
|
|
|
void
|
|
fuse_debug_write_out(const uint64_t unique_,
|
|
const struct fuse_write_out *arg_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
fmt::print(output.get(),
|
|
"ts={}"
|
|
" dir=OUT"
|
|
" unique=0x{:016X}"
|
|
" error=0"
|
|
" len={}"
|
|
" size={}"
|
|
"\n",
|
|
_timestamp_ns(),
|
|
unique_,
|
|
sizeof(struct fuse_write_out),
|
|
arg_->size);
|
|
}
|
|
|
|
void
|
|
fuse_debug_statfs_out(const uint64_t unique_,
|
|
const struct fuse_statfs_out *arg_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
fmt::print(output.get(),
|
|
"ts={}"
|
|
" dir=OUT"
|
|
" unique=0x{:016X}"
|
|
" error=0"
|
|
" len={}"
|
|
" blocks={}"
|
|
" bfree={}"
|
|
" bavail={}"
|
|
" files={}"
|
|
" ffree={}"
|
|
" bsize={}"
|
|
" namelen={}"
|
|
" frsize={}"
|
|
"\n",
|
|
_timestamp_ns(),
|
|
unique_,
|
|
sizeof(struct fuse_statfs_out),
|
|
arg_->st.blocks,
|
|
arg_->st.bfree,
|
|
arg_->st.bavail,
|
|
arg_->st.files,
|
|
arg_->st.ffree,
|
|
arg_->st.bsize,
|
|
arg_->st.namelen,
|
|
arg_->st.frsize);
|
|
}
|
|
|
|
void
|
|
fuse_debug_getxattr_out(const uint64_t unique_,
|
|
const struct fuse_getxattr_out *arg_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
fmt::print(output.get(),
|
|
"ts={}"
|
|
" dir=OUT"
|
|
" unique=0x{:016X}"
|
|
" error=0"
|
|
" len={}"
|
|
" size={}"
|
|
"\n",
|
|
_timestamp_ns(),
|
|
unique_,
|
|
sizeof(struct fuse_out_header) + sizeof(struct fuse_getxattr_out),
|
|
arg_->size);
|
|
}
|
|
|
|
void
|
|
fuse_debug_lk_out(const uint64_t unique_,
|
|
const struct fuse_lk_out *arg_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
fmt::print(output.get(),
|
|
"ts={}"
|
|
" dir=OUT"
|
|
" unique=0x{:016X}"
|
|
" error=0"
|
|
" len={}"
|
|
" lk_start={}"
|
|
" lk_end={}"
|
|
" lk_type={}"
|
|
" lk_pid={}"
|
|
"\n",
|
|
_timestamp_ns(),
|
|
unique_,
|
|
sizeof(struct fuse_out_header) + sizeof(struct fuse_lk_out),
|
|
arg_->lk.start,
|
|
arg_->lk.end,
|
|
arg_->lk.type,
|
|
arg_->lk.pid);
|
|
}
|
|
|
|
void
|
|
fuse_debug_bmap_out(const uint64_t unique_,
|
|
const struct fuse_bmap_out *arg_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
fmt::print(output.get(),
|
|
"ts={}"
|
|
" dir=OUT"
|
|
" unique=0x{:016X}"
|
|
" error=0"
|
|
" len={}"
|
|
" block={}"
|
|
"\n",
|
|
_timestamp_ns(),
|
|
unique_,
|
|
sizeof(struct fuse_out_header) + sizeof(struct fuse_bmap_out),
|
|
arg_->block);
|
|
}
|
|
|
|
void
|
|
fuse_debug_statx_out(const uint64_t unique_,
|
|
const struct fuse_statx_out *arg_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
fmt::print(output.get(),
|
|
"ts={}"
|
|
" dir=OUT"
|
|
" unique=0x{:016X}"
|
|
" error=0"
|
|
" len={}"
|
|
" attr_valid={}"
|
|
" attr_valid_nsec={}"
|
|
" flags=0x{:X}"
|
|
" ino=0x{:016X}"
|
|
" size={}"
|
|
" blocks={}"
|
|
" mode={:o}"
|
|
" nlink={}"
|
|
" uid={}"
|
|
" gid={}"
|
|
" blksize={}"
|
|
"\n",
|
|
_timestamp_ns(),
|
|
unique_,
|
|
sizeof(struct fuse_out_header) + sizeof(struct fuse_statx_out),
|
|
arg_->attr_valid,
|
|
arg_->attr_valid_nsec,
|
|
arg_->flags,
|
|
arg_->stat.ino,
|
|
arg_->stat.size,
|
|
arg_->stat.blocks,
|
|
arg_->stat.mode,
|
|
arg_->stat.nlink,
|
|
arg_->stat.uid,
|
|
arg_->stat.gid,
|
|
arg_->stat.blksize);
|
|
}
|
|
|
|
void
|
|
fuse_debug_data_out(const uint64_t unique_,
|
|
const size_t size_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
fmt::print(output.get(),
|
|
"ts={}"
|
|
" dir=OUT"
|
|
" unique=0x{:016X}"
|
|
" error=0"
|
|
" len={}"
|
|
" data_size={}"
|
|
"\n",
|
|
_timestamp_ns(),
|
|
unique_,
|
|
sizeof(struct fuse_out_header) + size_,
|
|
size_);
|
|
}
|
|
|
|
void
|
|
fuse_debug_ioctl_out(const uint64_t unique_,
|
|
const struct fuse_ioctl_out *arg_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
fmt::print(output.get(),
|
|
"ts={}"
|
|
" dir=OUT"
|
|
" unique=0x{:016X}"
|
|
" error=0"
|
|
" len={}"
|
|
" result={}"
|
|
" flags=0x{:X}"
|
|
" in_iovs={}"
|
|
" out_iovs={}"
|
|
"\n",
|
|
_timestamp_ns(),
|
|
unique_,
|
|
sizeof(struct fuse_out_header) + sizeof(struct fuse_ioctl_out),
|
|
arg_->result,
|
|
arg_->flags,
|
|
arg_->in_iovs,
|
|
arg_->out_iovs);
|
|
}
|
|
|
|
void
|
|
fuse_debug_poll_out(const uint64_t unique_,
|
|
const struct fuse_poll_out *arg_)
|
|
{
|
|
auto output = fuse_cfg.log_file();
|
|
|
|
fmt::print(output.get(),
|
|
"ts={}"
|
|
" dir=OUT"
|
|
" unique=0x{:016X}"
|
|
" error=0"
|
|
" len={}"
|
|
" revents=0x{:X}"
|
|
"\n",
|
|
_timestamp_ns(),
|
|
unique_,
|
|
sizeof(struct fuse_out_header) + sizeof(struct fuse_poll_out),
|
|
arg_->revents);
|
|
}
|