mirror of
https://github.com/trapexit/mergerfs.git
synced 2026-10-19 16:16:48 +00:00
Add mergerfs.collect-info (#1491)
A tool to collect info for support requests.
This commit is contained in:
@@ -137,6 +137,7 @@ build/tests: build/mergerfs tests-objects
|
||||
|
||||
mergerfs: build/mergerfs
|
||||
ln -fs "mergerfs" "build/fsck.mergerfs"
|
||||
ln -fs "mergerfs" "build/mergerfs.collect-info"
|
||||
|
||||
tests: build/tests
|
||||
|
||||
@@ -184,6 +185,7 @@ install-base: build/mergerfs
|
||||
$(MKDIR) -p "$(INSTALLBINDIR)"
|
||||
$(INSTALL) -v -m 0755 "build/mergerfs" "$(INSTALLBINDIR)/mergerfs"
|
||||
ln -s "mergerfs" "${INSTALLBINDIR}/fsck.mergerfs"
|
||||
ln -s "mergerfs" "${INSTALLBINDIR}/mergerfs.collect-info"
|
||||
|
||||
install-mount-tools: install-base
|
||||
$(MKDIR) -p "$(INSTALLBINDIR)"
|
||||
|
||||
@@ -35,6 +35,7 @@ make install PREFIX=%{_prefix} DESTDIR=%{buildroot}
|
||||
/usr/bin/mergerfs
|
||||
/usr/bin/mergerfs-fusermount
|
||||
/usr/bin/fsck.mergerfs
|
||||
/usr/bin/mergerfs.collect-info
|
||||
/sbin/mount.mergerfs
|
||||
/usr/lib/mergerfs/preload.so
|
||||
%doc %{_mandir}/*
|
||||
|
||||
Executable
+7
@@ -0,0 +1,7 @@
|
||||
#!/bin/sh
|
||||
set -x
|
||||
set -e
|
||||
|
||||
python3 -m venv venv
|
||||
. ./venv/bin/activate
|
||||
pip3 install --no-cache-dir mkdocs mkdocs-material pymdown-extensions mike
|
||||
+22
-14
@@ -7,7 +7,7 @@ otherwise it will be difficult or impossible to diagnose. Also please
|
||||
read the documentation as it provides details on many previously
|
||||
encountered questions/issues.
|
||||
|
||||
**Please make sure you are using the [latest
|
||||
**Make sure you are using the [latest
|
||||
release](https://github.com/trapexit/mergerfs/releases) or have tried
|
||||
it in comparison. Old versions, which are often included in distros
|
||||
like Debian and Ubuntu, are not ever going to be updated and the issue
|
||||
@@ -16,27 +16,35 @@ you are encountering may have been addressed already.**
|
||||
**For commercial support or feature requests please [contact me
|
||||
directly.](mailto:support@spawn.link)**
|
||||
|
||||
|
||||
### Information to include in bug reports
|
||||
|
||||
* [Information about the broader problem along with any attempted
|
||||
solutions.](https://xyproblem.info)
|
||||
* Solution already ruled out and why.
|
||||
* Version of mergerfs: `mergerfs --version`
|
||||
* mergerfs settings / arguments: from fstab, systemd unit, command
|
||||
line, OMV plugin, etc.
|
||||
* Version of the OS: `uname -a` and `lsb_release -a`
|
||||
* List of branches, their filesystem types, sizes (before and after issue): `df -h`
|
||||
* The details from the output of the `mergerfs.collect-info` tool.
|
||||
* Alternatively:
|
||||
* Version of mergerfs: `mergerfs --version`
|
||||
* mergerfs settings / arguments: from fstab, systemd unit, command
|
||||
line, OMV plugin, etc.
|
||||
* Version of the OS: `uname -a` and `lsb_release -a`
|
||||
* List of branches, their filesystem types, sizes (before and after
|
||||
issue): `df -h`, `lsblk -o NAME,FSTYPE,FSSIZE,SIZE,MOUNTPOINTS,RM,RO,ROTA`
|
||||
* **All** information about the relevant paths and files: permissions, ownership, etc.
|
||||
* **All** information about the client app making the requests: version, uid/gid
|
||||
* **All** information about the application making the requests: version, uid/gid
|
||||
* Runtime environment:
|
||||
* Is mergerfs running within a container?
|
||||
* Are the client apps using mergerfs running in a container?
|
||||
* Is mergerfs running within a container?
|
||||
* Are the client apps using mergerfs running in a container?
|
||||
* A `strace` of the app having problems:
|
||||
* `strace -fvTtt -s 256 -o /tmp/app.strace.txt <cmd>`
|
||||
* A `strace` of mergerfs while the program is trying to do whatever it is failing to do:
|
||||
* `strace -fvTtt -s 256 -p <mergerfsPID> -o /tmp/mergerfs.strace.txt`
|
||||
* **Precise** directions on replicating the issue. Do not leave **anything** out.
|
||||
* Try to recreate the problem in the simplest way using standard programs: `ln`, `mv`, `cp`, `ls`, `dd`, etc.
|
||||
* `strace -fvTtt -s 256 -o /tmp/app.strace.txt <cmd>`
|
||||
* A `strace` of mergerfs while the program is trying to do whatever it
|
||||
is failing to do:
|
||||
* `strace -fvTtt -s 256 -p <mergerfsPID> -o /tmp/mergerfs.strace.txt`
|
||||
* **Precise** directions on replicating the issue. Do not leave
|
||||
**anything** out.
|
||||
* Try to recreate the problem in the simplest way using standard
|
||||
programs: `ln`, `mv`, `cp`, `ls`, `dd`, etc. With the most simple
|
||||
mergerfs setup possible.
|
||||
|
||||
### Contact / Issue submission
|
||||
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
namespace fsck
|
||||
{
|
||||
int main(int argc, char **argv);
|
||||
}
|
||||
+7
-4
@@ -15,7 +15,8 @@
|
||||
*/
|
||||
|
||||
#include "mergerfs.hpp"
|
||||
#include "fsck_mergerfs.hpp"
|
||||
#include "mergerfs_fsck.hpp"
|
||||
#include "mergerfs_collect_info.hpp"
|
||||
|
||||
#include "fs_path.hpp"
|
||||
#include "fs_readahead.hpp"
|
||||
@@ -272,8 +273,8 @@ namespace l
|
||||
}
|
||||
|
||||
int
|
||||
main(const int argc_,
|
||||
char **argv_)
|
||||
main(int argc_,
|
||||
char **argv_)
|
||||
{
|
||||
int rv;
|
||||
Config::Read cfg;
|
||||
@@ -339,7 +340,9 @@ _pick_app_and_run(int argc_,
|
||||
appname = appname.filename();
|
||||
|
||||
if(appname == "fsck.mergerfs")
|
||||
return fsck::main(argc_,argv_);
|
||||
return mergerfs::fsck::main(argc_,argv_);
|
||||
if(appname == "mergerfs.collect-info")
|
||||
return mergerfs::collect_info::main(argc_,argv_);
|
||||
|
||||
return l::main(argc_,argv_);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
#include "mergerfs_api.hpp"
|
||||
|
||||
#include "fs_close.hpp"
|
||||
#include "fs_ioctl.hpp"
|
||||
#include "fs_open.hpp"
|
||||
#include "mergerfs_ioctl.hpp"
|
||||
#include "fs_lgetxattr.hpp"
|
||||
|
||||
#include "str.hpp"
|
||||
|
||||
#include "scope_guard.hpp"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
int
|
||||
mergerfs::api::allpaths(const std::string &input_path_,
|
||||
std::vector<std::string> &output_paths_)
|
||||
{
|
||||
int rv;
|
||||
IOCTL_BUF buf;
|
||||
|
||||
rv = fs::lgetxattr(input_path_,"user.mergerfs.allpaths",buf,sizeof(buf));
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
|
||||
str::split_on_null(buf,rv,&output_paths_);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
_lgetxattr(const std::string &input_path_,
|
||||
const std::string &key_,
|
||||
std::string &value_)
|
||||
{
|
||||
int rv;
|
||||
IOCTL_BUF buf;
|
||||
|
||||
rv = fs::lgetxattr(input_path_,key_,buf,sizeof(buf));
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
|
||||
value_ = buf;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int
|
||||
mergerfs::api::basepath(const std::string &input_path_,
|
||||
std::string &basepath_)
|
||||
{
|
||||
return ::_lgetxattr(input_path_,"user.mergerfs.basepath",basepath_);
|
||||
}
|
||||
|
||||
int
|
||||
mergerfs::api::relpath(const std::string &input_path_,
|
||||
std::string &relpath_)
|
||||
{
|
||||
return ::_lgetxattr(input_path_,"user.mergerfs.relpath",relpath_);
|
||||
}
|
||||
|
||||
int
|
||||
mergerfs::api::fullpath(const std::string &input_path_,
|
||||
std::string &fullpath_)
|
||||
{
|
||||
return ::_lgetxattr(input_path_,"user.mergerfs.fullpath",fullpath_);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace mergerfs
|
||||
{
|
||||
namespace api
|
||||
{
|
||||
int
|
||||
basepath(const std::string &path,
|
||||
std::string &basepath);
|
||||
int
|
||||
relpath(const std::string &path,
|
||||
std::string &relpath);
|
||||
int
|
||||
fullpath(const std::string &path,
|
||||
std::string &fullpath);
|
||||
int
|
||||
allpaths(const std::string &path,
|
||||
std::vector<std::string> &paths);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
#include "mergerfs_collect_info.hpp"
|
||||
|
||||
#include "mergerfs_api.hpp"
|
||||
#include "fs_mounts.hpp"
|
||||
#include "fs_unlink.hpp"
|
||||
|
||||
#include "CLI11.hpp"
|
||||
#include "fmt/core.h"
|
||||
#include "scope_guard.hpp"
|
||||
#include "subprocess.hpp"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
static
|
||||
void
|
||||
_write_str(const std::string &output_,
|
||||
const std::string &str_)
|
||||
{
|
||||
FILE *f;
|
||||
|
||||
f = ::fopen(output_.c_str(),"a");
|
||||
if(f == NULL)
|
||||
return;
|
||||
DEFER{ ::fclose(f); };
|
||||
|
||||
::fwrite(str_.c_str(),1,str_.size(),f);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
_lsblk(const std::string &output_)
|
||||
{
|
||||
auto args =
|
||||
{
|
||||
"lsblk",
|
||||
"--json",
|
||||
"-o","NAME,FSTYPE,FSSIZE,SIZE,MOUNTPOINTS,RM,RO,ROTA"
|
||||
};
|
||||
|
||||
subprocess::call(args,
|
||||
subprocess::output{output_.c_str()});
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
_mounts(const std::string &output_)
|
||||
{
|
||||
auto args =
|
||||
{
|
||||
"cat",
|
||||
"/proc/mounts"
|
||||
};
|
||||
|
||||
subprocess::call(args,
|
||||
subprocess::output{output_.c_str()});
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
_mount_point_stats(const std::string &output_)
|
||||
{
|
||||
fs::MountVec mounts;
|
||||
|
||||
fs::mounts(mounts);
|
||||
|
||||
for(const auto &mount : mounts)
|
||||
{
|
||||
std::vector<std::string> allpaths;
|
||||
|
||||
mergerfs::api::allpaths(mount.dir.string(),allpaths);
|
||||
for(const auto &path : allpaths)
|
||||
{
|
||||
auto args = {"stat",path.c_str()};
|
||||
subprocess::call(args,
|
||||
subprocess::output{output_.c_str()});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
_mergerfs_version(const std::string &output_)
|
||||
{
|
||||
auto args =
|
||||
{
|
||||
"mergerfs",
|
||||
"--version"
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
subprocess::call(args,
|
||||
subprocess::output{output_.c_str()});
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
_uname(const std::string &output_)
|
||||
{
|
||||
auto args =
|
||||
{
|
||||
"uname",
|
||||
"-a"
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
subprocess::call(args,
|
||||
subprocess::output{output_.c_str()});
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
_lsb_release(const std::string &output_)
|
||||
{
|
||||
auto args =
|
||||
{
|
||||
"lsb_release",
|
||||
"-a"
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
subprocess::call(args,
|
||||
subprocess::output{output_.c_str()});
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
_df(const std::string &output_)
|
||||
{
|
||||
auto args =
|
||||
{
|
||||
"df",
|
||||
"-h"
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
subprocess::call(args,
|
||||
subprocess::output{output_.c_str()});
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
_fstab(const std::string &output_)
|
||||
{
|
||||
auto args =
|
||||
{
|
||||
"cat",
|
||||
"/etc/fstab"
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
subprocess::call(args,
|
||||
subprocess::output{output_.c_str()});
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
mergerfs::collect_info::main(int argc_,
|
||||
char **argv_)
|
||||
{
|
||||
CLI::App app;
|
||||
const char *output_filepath = "/tmp/mergerfs.info.txt";
|
||||
|
||||
app.description("mergerfs.collect-info:"
|
||||
" Collect info for support requests");
|
||||
app.name("USAGE: mergerfs.collect-info");
|
||||
|
||||
try
|
||||
{
|
||||
app.parse(argc_,argv_);
|
||||
}
|
||||
catch(const CLI::ParseError &e)
|
||||
{
|
||||
return app.exit(e);
|
||||
}
|
||||
|
||||
fmt::print("* Please have mergerfs mounted before running this tool.\n");
|
||||
|
||||
fs::unlink(output_filepath);
|
||||
::_write_str(output_filepath,"::mergerfs --version::\n");
|
||||
::_mergerfs_version(output_filepath);
|
||||
::_write_str(output_filepath,"\n::uname -a::\n");
|
||||
::_uname(output_filepath);
|
||||
::_write_str(output_filepath,"\n::lsb_release -a::\n");
|
||||
::_lsb_release(output_filepath);
|
||||
::_write_str(output_filepath,"\n::df -h::\n");
|
||||
::_df(output_filepath);
|
||||
::_write_str(output_filepath,"\n::lsblk::\n");
|
||||
::_lsblk(output_filepath);
|
||||
::_write_str(output_filepath,"\n::cat /proc/mounts::\n");
|
||||
::_mounts(output_filepath);
|
||||
::_write_str(output_filepath,"\n::mount point stats::\n");
|
||||
::_mount_point_stats(output_filepath);
|
||||
::_write_str(output_filepath,"\n::cat /etc/fstab::\n");
|
||||
::_fstab(output_filepath);
|
||||
|
||||
fmt::print("* Upload the following file to your"
|
||||
" GitHub ticket or put on https://pastebin.com"
|
||||
" when requesting support.\n* {}\n",output_filepath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
namespace mergerfs
|
||||
{
|
||||
namespace collect_info
|
||||
{
|
||||
int
|
||||
main(int argc,
|
||||
char **argv);
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,15 @@
|
||||
#include "fsck_mergerfs.hpp"
|
||||
#include "mergerfs_fsck.hpp"
|
||||
|
||||
#include "fs_lchmod.hpp"
|
||||
#include "fs_lchown.hpp"
|
||||
#include "fs_close.hpp"
|
||||
#include "fs_ioctl.hpp"
|
||||
#include "fs_lgetxattr.hpp"
|
||||
#include "fs_lstat.hpp"
|
||||
#include "fs_open.hpp"
|
||||
#include "int_types.h"
|
||||
#include "mergerfs_ioctl.hpp"
|
||||
#include "str.hpp"
|
||||
#include "fs_copyfile.hpp"
|
||||
#include "mergerfs_api.hpp"
|
||||
|
||||
#include "fmt/core.h"
|
||||
#include "fmt/chrono.h"
|
||||
@@ -169,22 +168,13 @@ int
|
||||
_get_allpaths(const std::string &mergerfs_path_,
|
||||
PathStatVec &pathstats_)
|
||||
{
|
||||
int fd;
|
||||
int rv;
|
||||
IOCTL_BUF buf;
|
||||
std::vector<std::string> allpaths;
|
||||
|
||||
strcpy(buf,"allpaths");
|
||||
rv = mergerfs::api::allpaths(mergerfs_path_,allpaths);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
|
||||
fd = fs::open(mergerfs_path_,O_RDONLY|O_NOFOLLOW);
|
||||
if(fd == -1)
|
||||
return -errno;
|
||||
|
||||
rv = fs::ioctl(fd,IOCTL_FILE_INFO,buf);
|
||||
|
||||
fs::close(fd);
|
||||
|
||||
str::split_on_null(buf,rv,&allpaths);
|
||||
for(const auto &path : allpaths)
|
||||
pathstats_.emplace_back(path);
|
||||
|
||||
@@ -396,8 +386,8 @@ _fsck(const FS::path &path_,
|
||||
}
|
||||
|
||||
int
|
||||
fsck::main(int argc_,
|
||||
char **argv_)
|
||||
mergerfs::fsck::main(int argc_,
|
||||
char **argv_)
|
||||
{
|
||||
CLI::App app;
|
||||
FS::path path;
|
||||
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
namespace mergerfs
|
||||
{
|
||||
namespace fsck
|
||||
{
|
||||
int main(int argc, char **argv);
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,12 @@
|
||||
#define _IOC_TYPE(X) (((X) >> 8) & 0xFF)
|
||||
#endif
|
||||
|
||||
typedef char IOCTL_BUF[4096];
|
||||
#ifndef _IOC_SIZEBITS
|
||||
#define _IOC_SIZEBITS 14
|
||||
#endif
|
||||
|
||||
#define IOCTL_BUF_SIZE ((1 << _IOC_SIZEBITS) - 1)
|
||||
typedef char IOCTL_BUF[IOCTL_BUF_SIZE];
|
||||
#define IOCTL_APP_TYPE 0xDF
|
||||
#define IOCTL_FILE_INFO _IOWR(IOCTL_APP_TYPE,0,IOCTL_BUF)
|
||||
#define IOCTL_GC _IO(IOCTL_APP_TYPE,1)
|
||||
|
||||
Reference in New Issue
Block a user