Merge pull request #1123 from trapexit/wait

Add option to wait for branches to become new mounts
This commit is contained in:
trapexit 2023-01-25 19:51:58 -05:00 committed by GitHub
commit 16e9ba2f19
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 3034 additions and 106 deletions

View File

@ -1,7 +1,7 @@
/* /*
ISC License ISC License
Copyright (c) 2021, Antonio SJ Musumeci <trapexit@spawn.link> Copyright (c) 2023, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above purpose with or without fee is hereby granted, provided that the above

View File

@ -1,6 +1,6 @@
% mergerfs(1) mergerfs user manual % mergerfs(1) mergerfs user manual
% Antonio SJ Musumeci <trapexit@spawn.link> % Antonio SJ Musumeci <trapexit@spawn.link>
% 2023-01-16 % 2023-01-24
# NAME # NAME
@ -165,6 +165,9 @@ These options are the same regardless of whether you use them with the `mergerfs
* **nfsopenhack=off|git|all**: A workaround for exporting mergerfs * **nfsopenhack=off|git|all**: A workaround for exporting mergerfs
over NFS where there are issues with creating files for write while over NFS where there are issues with creating files for write while
setting the mode to read-only. (default: off) setting the mode to read-only. (default: off)
* **branches-mount-timeout=UINT**: Number of seconds to wait at
startup for branches to be a mount other than the mountpoint's
filesystem. (default: 0)
* **follow-symlinks=never|directory|regular|all**: Turns symlinks into * **follow-symlinks=never|directory|regular|all**: Turns symlinks into
what they point to. (default: never) what they point to. (default: never)
* **link-exdev=passthrough|rel-symlink|abs-base-symlink|abs-pool-symlink**: * **link-exdev=passthrough|rel-symlink|abs-base-symlink|abs-pool-symlink**:

View File

@ -363,6 +363,17 @@ Branches::Impl::to_paths(StrVec &paths_) const
} }
} }
fs::PathVector
Branches::Impl::to_paths() const
{
fs::PathVector vp;
for(const auto &branch : *this)
vp.emplace_back(branch.path);
return vp;
}
int int
Branches::from_string(const std::string &str_) Branches::from_string(const std::string &str_)
{ {

View File

@ -19,7 +19,7 @@
#pragma once #pragma once
#include "branch.hpp" #include "branch.hpp"
#include "nonstd/optional.hpp" #include "fs_pathvector.hpp"
#include "strvec.hpp" #include "strvec.hpp"
#include "tofrom_string.hpp" #include "tofrom_string.hpp"
@ -49,6 +49,7 @@ public:
public: public:
const uint64_t& minfreespace(void) const; const uint64_t& minfreespace(void) const;
void to_paths(StrVec &strvec) const; void to_paths(StrVec &strvec) const;
fs::PathVector to_paths() const;
public: public:
Impl& operator=(Impl &impl_); Impl& operator=(Impl &impl_);

View File

@ -53,6 +53,7 @@ namespace l
readonly(const std::string &s_) readonly(const std::string &s_)
{ {
IFERT("async_read"); IFERT("async_read");
IFERT("branches-mount-timeout");
IFERT("cache.symlinks"); IFERT("cache.symlinks");
IFERT("cache.writeback"); IFERT("cache.writeback");
IFERT("fsname"); IFERT("fsname");
@ -73,6 +74,7 @@ Config::Config()
auto_cache(false), auto_cache(false),
minfreespace(MINFREESPACE_DEFAULT), minfreespace(MINFREESPACE_DEFAULT),
branches(minfreespace), branches(minfreespace),
branches_mount_timeout(0),
cache_attr(1), cache_attr(1),
cache_entry(1), cache_entry(1),
cache_files(CacheFiles::ENUM::LIBFUSE), cache_files(CacheFiles::ENUM::LIBFUSE),
@ -113,72 +115,73 @@ Config::Config()
writeback_cache(false), writeback_cache(false),
xattr(XAttr::ENUM::PASSTHROUGH) xattr(XAttr::ENUM::PASSTHROUGH)
{ {
_map["async_read"] = &async_read; _map["async_read"] = &async_read;
_map["auto_cache"] = &auto_cache; _map["auto_cache"] = &auto_cache;
_map["branches"] = &branches; _map["branches"] = &branches;
_map["cache.attr"] = &cache_attr; _map["branches-mount-timeout"] = &branches_mount_timeout;
_map["cache.entry"] = &cache_entry; _map["cache.attr"] = &cache_attr;
_map["cache.files"] = &cache_files; _map["cache.entry"] = &cache_entry;
_map["cache.negative_entry"] = &cache_negative_entry; _map["cache.files"] = &cache_files;
_map["cache.readdir"] = &cache_readdir; _map["cache.negative_entry"] = &cache_negative_entry;
_map["cache.statfs"] = &cache_statfs; _map["cache.readdir"] = &cache_readdir;
_map["cache.symlinks"] = &cache_symlinks; _map["cache.statfs"] = &cache_statfs;
_map["cache.writeback"] = &writeback_cache; _map["cache.symlinks"] = &cache_symlinks;
_map["category.action"] = &category.action; _map["cache.writeback"] = &writeback_cache;
_map["category.create"] = &category.create; _map["category.action"] = &category.action;
_map["category.search"] = &category.search; _map["category.create"] = &category.create;
_map["direct_io"] = &direct_io; _map["category.search"] = &category.search;
_map["dropcacheonclose"] = &dropcacheonclose; _map["direct_io"] = &direct_io;
_map["follow-symlinks"] = &follow_symlinks; _map["dropcacheonclose"] = &dropcacheonclose;
_map["fsname"] = &fsname; _map["follow-symlinks"] = &follow_symlinks;
_map["func.access"] = &func.access; _map["fsname"] = &fsname;
_map["func.chmod"] = &func.chmod; _map["func.access"] = &func.access;
_map["func.chown"] = &func.chown; _map["func.chmod"] = &func.chmod;
_map["func.create"] = &func.create; _map["func.chown"] = &func.chown;
_map["func.getattr"] = &func.getattr; _map["func.create"] = &func.create;
_map["func.getxattr"] = &func.getxattr; _map["func.getattr"] = &func.getattr;
_map["func.link"] = &func.link; _map["func.getxattr"] = &func.getxattr;
_map["func.listxattr"] = &func.listxattr; _map["func.link"] = &func.link;
_map["func.mkdir"] = &func.mkdir; _map["func.listxattr"] = &func.listxattr;
_map["func.mknod"] = &func.mknod; _map["func.mkdir"] = &func.mkdir;
_map["func.open"] = &func.open; _map["func.mknod"] = &func.mknod;
_map["func.readlink"] = &func.readlink; _map["func.open"] = &func.open;
_map["func.removexattr"] = &func.removexattr; _map["func.readlink"] = &func.readlink;
_map["func.rename"] = &func.rename; _map["func.removexattr"] = &func.removexattr;
_map["func.rmdir"] = &func.rmdir; _map["func.rename"] = &func.rename;
_map["func.setxattr"] = &func.setxattr; _map["func.rmdir"] = &func.rmdir;
_map["func.symlink"] = &func.symlink; _map["func.setxattr"] = &func.setxattr;
_map["func.truncate"] = &func.truncate; _map["func.symlink"] = &func.symlink;
_map["func.unlink"] = &func.unlink; _map["func.truncate"] = &func.truncate;
_map["func.utimens"] = &func.utimens; _map["func.unlink"] = &func.unlink;
_map["fuse_msg_size"] = &fuse_msg_size; _map["func.utimens"] = &func.utimens;
_map["ignorepponrename"] = &ignorepponrename; _map["fuse_msg_size"] = &fuse_msg_size;
_map["inodecalc"] = &inodecalc; _map["ignorepponrename"] = &ignorepponrename;
_map["kernel_cache"] = &kernel_cache; _map["inodecalc"] = &inodecalc;
_map["link_cow"] = &link_cow; _map["kernel_cache"] = &kernel_cache;
_map["link-exdev"] = &link_exdev; _map["link_cow"] = &link_cow;
_map["log.metrics"] = &log_metrics; _map["link-exdev"] = &link_exdev;
_map["minfreespace"] = &minfreespace; _map["log.metrics"] = &log_metrics;
_map["mount"] = &mount; _map["minfreespace"] = &minfreespace;
_map["moveonenospc"] = &moveonenospc; _map["mount"] = &mount;
_map["nfsopenhack"] = &nfsopenhack; _map["moveonenospc"] = &moveonenospc;
_map["nullrw"] = &nullrw; _map["nfsopenhack"] = &nfsopenhack;
_map["pid"] = &pid; _map["nullrw"] = &nullrw;
_map["posix_acl"] = &posix_acl; _map["pid"] = &pid;
// _map["readdir"] = &readdir; _map["posix_acl"] = &posix_acl;
_map["readdirplus"] = &readdirplus; // _map["readdir"] = &readdir;
_map["rename-exdev"] = &rename_exdev; _map["readdirplus"] = &readdirplus;
_map["security_capability"] = &security_capability; _map["rename-exdev"] = &rename_exdev;
_map["srcmounts"] = &srcmounts; _map["security_capability"] = &security_capability;
_map["statfs"] = &statfs; _map["srcmounts"] = &srcmounts;
_map["statfs_ignore"] = &statfs_ignore; _map["statfs"] = &statfs;
_map["symlinkify"] = &symlinkify; _map["statfs_ignore"] = &statfs_ignore;
_map["symlinkify_timeout"] = &symlinkify_timeout; _map["symlinkify"] = &symlinkify;
_map["threads"] = &fuse_read_thread_count; _map["symlinkify_timeout"] = &symlinkify_timeout;
_map["read-thread-count"] = &fuse_read_thread_count; _map["threads"] = &fuse_read_thread_count;
_map["process-thread-count"] = &fuse_process_thread_count; _map["read-thread-count"] = &fuse_read_thread_count;
_map["version"] = &version; _map["process-thread-count"] = &fuse_process_thread_count;
_map["xattr"] = &xattr; _map["version"] = &version;
_map["xattr"] = &xattr;
} }
Config& Config&

View File

@ -103,6 +103,7 @@ public:
ConfigBOOL auto_cache; ConfigBOOL auto_cache;
ConfigUINT64 minfreespace; ConfigUINT64 minfreespace;
Branches branches; Branches branches;
ConfigUINT64 branches_mount_timeout;
ConfigUINT64 cache_attr; ConfigUINT64 cache_attr;
ConfigUINT64 cache_entry; ConfigUINT64 cache_entry;
CacheFiles cache_files; CacheFiles cache_files;

10
src/fs_pathvector.hpp Normal file
View File

@ -0,0 +1,10 @@
#pragma once
#include "ghc/filesystem.hpp"
#include <vector>
namespace fs
{
typedef std::vector<ghc::filesystem::path> PathVector;
}

112
src/fs_wait_for_mount.cpp Normal file
View File

@ -0,0 +1,112 @@
/*
ISC License
Copyright (c) 2023, 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.
*/
#include "fs_wait_for_mount.hpp"
#include <thread>
constexpr std::chrono::milliseconds SLEEP_DURATION = std::chrono::milliseconds(333);
bool
fs::wait_for_mount(const struct stat &src_st_,
const ghc::filesystem::path &tgtpath_,
const std::chrono::milliseconds &timeout_)
{
int rv;
std::chrono::duration<double> time_diff;
std::chrono::time_point<std::chrono::steady_clock> start_time;
start_time = std::chrono::steady_clock::now();
while(true)
{
struct stat tgt_st;
rv = fs::stat(tgtpath_,&tgt_st);
if(rv == 0)
{
if(tgt_st.st_dev != src_st_.st_dev)
return true;
}
time_diff = (std::chrono::steady_clock::now() - start_time);
if(time_diff > timeout_)
return false;
std::this_thread::sleep_for(SLEEP_DURATION);
}
return false;
}
static
void
_wait_for_mount(const struct stat &src_st_,
const fs::PathVector &tgtpaths_,
const std::chrono::milliseconds &timeout_,
fs::PathVector &failed_paths_)
{
bool rv;
fs::PathVector::const_iterator i;
std::chrono::milliseconds timeout;
std::chrono::milliseconds diff;
std::chrono::time_point<std::chrono::steady_clock> now;
std::chrono::time_point<std::chrono::steady_clock> start_time;
timeout = timeout_;
now = start_time = std::chrono::steady_clock::now();
for(auto i = tgtpaths_.begin(); i != tgtpaths_.end(); ++i)
{
diff = std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time);
timeout -= diff;
rv = fs::wait_for_mount(src_st_,*i,timeout);
if(rv == false)
failed_paths_.push_back(*i);
now = std::chrono::steady_clock::now();
}
}
void
fs::wait_for_mount(const struct stat &src_st_,
const fs::PathVector &tgtpaths_,
const std::chrono::milliseconds &timeout_,
fs::PathVector &failed_paths_)
{
if(tgtpaths_.empty())
return;
_wait_for_mount(src_st_,tgtpaths_,timeout_,failed_paths_);
}
void
fs::wait_for_mount(const ghc::filesystem::path &srcpath_,
const fs::PathVector &tgtpaths_,
const std::chrono::milliseconds &timeout_,
fs::PathVector &failed_paths_)
{
int rv;
struct stat src_st;
rv = fs::stat(srcpath_,&src_st);
if(rv == -1)
return;
fs::wait_for_mount(src_st,tgtpaths_,timeout_,failed_paths_);
}

50
src/fs_wait_for_mount.hpp Normal file
View File

@ -0,0 +1,50 @@
/*
ISC License
Copyright (c) 2023, 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.
*/
#pragma once
#include "ghc/filesystem.hpp"
#include "fs_pathvector.hpp"
#include "fs_stat.hpp"
#include <chrono>
#include <vector>
namespace fs
{
typedef std::vector<ghc::filesystem::path> PathVector;
bool
wait_for_mount(const struct stat &st,
const ghc::filesystem::path &tgtpath,
const std::chrono::milliseconds &timeout);
void
wait_for_mount(const struct stat &st,
const fs::PathVector &tgtpaths,
const std::chrono::milliseconds &timeout,
fs::PathVector &failed_paths);
void
wait_for_mount(const ghc::filesystem::path &srcpath,
const fs::PathVector &tgtpaths,
const std::chrono::milliseconds &timeout,
fs::PathVector &failed_paths);
}

View File

@ -14,6 +14,9 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "fs_wait_for_mount.hpp"
#include "syslog.hpp"
#include "fs_path.hpp" #include "fs_path.hpp"
#include "mergerfs.hpp" #include "mergerfs.hpp"
#include "option_parser.hpp" #include "option_parser.hpp"
@ -147,6 +150,33 @@ namespace l
resources::setpriority(prio); resources::setpriority(prio);
} }
static
void
wait_for_mount(const Config::Read &cfg_)
{
fs::PathVector paths;
fs::PathVector failed;
std::chrono::milliseconds timeout;
paths = cfg_->branches->to_paths();
syslog_info("Waiting %u seconds for branches to mount",
(uint64_t)cfg_->branches_mount_timeout);
timeout = std::chrono::milliseconds(cfg_->branches_mount_timeout * 1000);
fs::wait_for_mount((std::string)cfg_->mount,
paths,
timeout,
failed);
for(auto &path : failed)
syslog_warning("Branch %s was not mounted within timeout",
path.c_str());
if(failed.size())
syslog_warning("Continuing to mount mergerfs despite %u branches not "
"being different from the mountpoint filesystem",
failed.size());
}
int int
main(const int argc_, main(const int argc_,
char **argv_) char **argv_)
@ -156,6 +186,8 @@ namespace l
fuse_args args; fuse_args args;
fuse_operations ops; fuse_operations ops;
syslog_open();
memset(&ops,0,sizeof(fuse_operations)); memset(&ops,0,sizeof(fuse_operations));
args.argc = argc_; args.argc = argc_;
@ -169,6 +201,9 @@ namespace l
return 1; return 1;
} }
if(cfg->branches_mount_timeout > 0)
l::wait_for_mount(cfg);
l::setup_resources(); l::setup_resources();
l::get_fuse_operations(ops,cfg->nullrw); l::get_fuse_operations(ops,cfg->nullrw);

2537
src/nonstd/expected.hpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -44,20 +44,26 @@
# define optional_CONFIG_SELECT_OPTIONAL ( optional_HAVE_STD_OPTIONAL ? optional_OPTIONAL_STD : optional_OPTIONAL_NONSTD ) # define optional_CONFIG_SELECT_OPTIONAL ( optional_HAVE_STD_OPTIONAL ? optional_OPTIONAL_STD : optional_OPTIONAL_NONSTD )
#endif #endif
// Control presence of extensions:
#ifndef optional_CONFIG_NO_EXTENSIONS
#define optional_CONFIG_NO_EXTENSIONS 0
#endif
// Control presence of exception handling (try and auto discover): // Control presence of exception handling (try and auto discover):
#ifndef optional_CONFIG_NO_EXCEPTIONS #ifndef optional_CONFIG_NO_EXCEPTIONS
# if defined(_MSC_VER) # if defined(_MSC_VER)
# include <cstddef> // for _HAS_EXCEPTIONS # include <cstddef> // for _HAS_EXCEPTIONS
# endif # endif
# if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || (_HAS_EXCEPTIONS) # if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || (defined(_HAS_EXCEPTIONS) && (_HAS_EXCEPTIONS))
# define optional_CONFIG_NO_EXCEPTIONS 0 # define optional_CONFIG_NO_EXCEPTIONS 0
# else # else
# define optional_CONFIG_NO_EXCEPTIONS 1 # define optional_CONFIG_NO_EXCEPTIONS 1
# endif # endif
#endif #endif
// C++ language version detection (C++20 is speculative): // C++ language version detection (C++23 is speculative):
// Note: VC14.0/1900 (VS2015) lacks too much from C++14. // Note: VC14.0/1900 (VS2015) lacks too much from C++14.
#ifndef optional_CPLUSPLUS #ifndef optional_CPLUSPLUS
@ -73,7 +79,8 @@
#define optional_CPP11_OR_GREATER_ ( optional_CPLUSPLUS >= 201103L ) #define optional_CPP11_OR_GREATER_ ( optional_CPLUSPLUS >= 201103L )
#define optional_CPP14_OR_GREATER ( optional_CPLUSPLUS >= 201402L ) #define optional_CPP14_OR_GREATER ( optional_CPLUSPLUS >= 201402L )
#define optional_CPP17_OR_GREATER ( optional_CPLUSPLUS >= 201703L ) #define optional_CPP17_OR_GREATER ( optional_CPLUSPLUS >= 201703L )
#define optional_CPP20_OR_GREATER ( optional_CPLUSPLUS >= 202000L ) #define optional_CPP20_OR_GREATER ( optional_CPLUSPLUS >= 202002L )
#define optional_CPP23_OR_GREATER ( optional_CPLUSPLUS >= 202300L )
// C++ language version (represent 98 as 3): // C++ language version (represent 98 as 3):
@ -782,7 +789,7 @@ union storage_t
void construct_value( value_type && v ) void construct_value( value_type && v )
{ {
::new( value_ptr() ) value_type( std::move( v ) ); ::new( const_cast<void *>(static_cast<const volatile void *>(value_ptr())) ) value_type( std::move( v ) );
} }
template< class... Args > template< class... Args >
@ -794,13 +801,13 @@ union storage_t
template< class... Args > template< class... Args >
void emplace( Args&&... args ) void emplace( Args&&... args )
{ {
::new( value_ptr() ) value_type( std::forward<Args>(args)... ); ::new( const_cast<void *>(static_cast<const volatile void *>(value_ptr())) ) value_type( std::forward<Args>(args)... );
} }
template< class U, class... Args > template< class U, class... Args >
void emplace( std::initializer_list<U> il, Args&&... args ) void emplace( std::initializer_list<U> il, Args&&... args )
{ {
::new( value_ptr() ) value_type( il, std::forward<Args>(args)... ); ::new( const_cast<void *>(static_cast<const volatile void *>(value_ptr())) ) value_type( il, std::forward<Args>(args)... );
} }
#endif #endif
@ -1485,7 +1492,40 @@ public:
return has_value() ? contained.value() : static_cast<value_type>( v ); return has_value() ? contained.value() : static_cast<value_type>( v );
} }
#endif // optional_CPP11_OR_GREATER #endif // optional_HAVE( REF_QUALIFIER )
#if !optional_CONFIG_NO_EXTENSIONS
#if optional_HAVE( REF_QUALIFIER )
template< typename F >
optional_constexpr value_type value_or_eval( F f ) const &
{
return has_value() ? contained.value() : f();
}
template< typename F >
optional_constexpr14 value_type value_or_eval( F f ) &&
{
if ( has_value() )
{
return std::move( contained.value() );
}
else
{
return f();
}
}
#else
template< typename F >
optional_constexpr value_type value_or_eval( F f ) const
{
return has_value() ? contained.value() : f();
}
#endif // optional_HAVE( REF_QUALIFIER )
#endif // !optional_CONFIG_NO_EXTENSIONS
// x.x.3.6, modifiers // x.x.3.6, modifiers
@ -1530,37 +1570,37 @@ private:
// Relational operators // Relational operators
template< typename T, typename U > template< typename T, typename U >
inline optional_constexpr bool operator==( optional<T> const & x, optional<U> const & y ) optional_nodiscard optional_constexpr bool operator==( optional<T> const & x, optional<U> const & y )
{ {
return bool(x) != bool(y) ? false : !bool( x ) ? true : *x == *y; return bool(x) != bool(y) ? false : !bool( x ) ? true : *x == *y;
} }
template< typename T, typename U > template< typename T, typename U >
inline optional_constexpr bool operator!=( optional<T> const & x, optional<U> const & y ) optional_nodiscard optional_constexpr bool operator!=( optional<T> const & x, optional<U> const & y )
{ {
return !(x == y); return !(x == y);
} }
template< typename T, typename U > template< typename T, typename U >
inline optional_constexpr bool operator<( optional<T> const & x, optional<U> const & y ) optional_nodiscard optional_constexpr bool operator<( optional<T> const & x, optional<U> const & y )
{ {
return (!y) ? false : (!x) ? true : *x < *y; return (!y) ? false : (!x) ? true : *x < *y;
} }
template< typename T, typename U > template< typename T, typename U >
inline optional_constexpr bool operator>( optional<T> const & x, optional<U> const & y ) optional_nodiscard optional_constexpr bool operator>( optional<T> const & x, optional<U> const & y )
{ {
return (y < x); return (y < x);
} }
template< typename T, typename U > template< typename T, typename U >
inline optional_constexpr bool operator<=( optional<T> const & x, optional<U> const & y ) optional_nodiscard optional_constexpr bool operator<=( optional<T> const & x, optional<U> const & y )
{ {
return !(y < x); return !(y < x);
} }
template< typename T, typename U > template< typename T, typename U >
inline optional_constexpr bool operator>=( optional<T> const & x, optional<U> const & y ) optional_nodiscard optional_constexpr bool operator>=( optional<T> const & x, optional<U> const & y )
{ {
return !(x < y); return !(x < y);
} }
@ -1568,73 +1608,73 @@ inline optional_constexpr bool operator>=( optional<T> const & x, optional<U> co
// Comparison with nullopt // Comparison with nullopt
template< typename T > template< typename T >
inline optional_constexpr bool operator==( optional<T> const & x, nullopt_t /*unused*/ ) optional_noexcept optional_nodiscard optional_constexpr bool operator==( optional<T> const & x, nullopt_t /*unused*/ ) optional_noexcept
{ {
return (!x); return (!x);
} }
template< typename T > template< typename T >
inline optional_constexpr bool operator==( nullopt_t /*unused*/, optional<T> const & x ) optional_noexcept optional_nodiscard optional_constexpr bool operator==( nullopt_t /*unused*/, optional<T> const & x ) optional_noexcept
{ {
return (!x); return (!x);
} }
template< typename T > template< typename T >
inline optional_constexpr bool operator!=( optional<T> const & x, nullopt_t /*unused*/ ) optional_noexcept optional_nodiscard optional_constexpr bool operator!=( optional<T> const & x, nullopt_t /*unused*/ ) optional_noexcept
{ {
return bool(x); return bool(x);
} }
template< typename T > template< typename T >
inline optional_constexpr bool operator!=( nullopt_t /*unused*/, optional<T> const & x ) optional_noexcept optional_nodiscard optional_constexpr bool operator!=( nullopt_t /*unused*/, optional<T> const & x ) optional_noexcept
{ {
return bool(x); return bool(x);
} }
template< typename T > template< typename T >
inline optional_constexpr bool operator<( optional<T> const & /*unused*/, nullopt_t /*unused*/ ) optional_noexcept optional_nodiscard optional_constexpr bool operator<( optional<T> const & /*unused*/, nullopt_t /*unused*/ ) optional_noexcept
{ {
return false; return false;
} }
template< typename T > template< typename T >
inline optional_constexpr bool operator<( nullopt_t /*unused*/, optional<T> const & x ) optional_noexcept optional_nodiscard optional_constexpr bool operator<( nullopt_t /*unused*/, optional<T> const & x ) optional_noexcept
{ {
return bool(x); return bool(x);
} }
template< typename T > template< typename T >
inline optional_constexpr bool operator<=( optional<T> const & x, nullopt_t /*unused*/ ) optional_noexcept optional_nodiscard optional_constexpr bool operator<=( optional<T> const & x, nullopt_t /*unused*/ ) optional_noexcept
{ {
return (!x); return (!x);
} }
template< typename T > template< typename T >
inline optional_constexpr bool operator<=( nullopt_t /*unused*/, optional<T> const & /*unused*/ ) optional_noexcept optional_nodiscard optional_constexpr bool operator<=( nullopt_t /*unused*/, optional<T> const & /*unused*/ ) optional_noexcept
{ {
return true; return true;
} }
template< typename T > template< typename T >
inline optional_constexpr bool operator>( optional<T> const & x, nullopt_t /*unused*/ ) optional_noexcept optional_nodiscard optional_constexpr bool operator>( optional<T> const & x, nullopt_t /*unused*/ ) optional_noexcept
{ {
return bool(x); return bool(x);
} }
template< typename T > template< typename T >
inline optional_constexpr bool operator>( nullopt_t /*unused*/, optional<T> const & /*unused*/ ) optional_noexcept optional_nodiscard optional_constexpr bool operator>( nullopt_t /*unused*/, optional<T> const & /*unused*/ ) optional_noexcept
{ {
return false; return false;
} }
template< typename T > template< typename T >
inline optional_constexpr bool operator>=( optional<T> const & /*unused*/, nullopt_t /*unused*/ ) optional_noexcept optional_nodiscard optional_constexpr bool operator>=( optional<T> const & /*unused*/, nullopt_t /*unused*/ ) optional_noexcept
{ {
return true; return true;
} }
template< typename T > template< typename T >
inline optional_constexpr bool operator>=( nullopt_t /*unused*/, optional<T> const & x ) optional_noexcept optional_nodiscard optional_constexpr bool operator>=( nullopt_t /*unused*/, optional<T> const & x ) optional_noexcept
{ {
return (!x); return (!x);
} }
@ -1642,73 +1682,73 @@ inline optional_constexpr bool operator>=( nullopt_t /*unused*/, optional<T> con
// Comparison with T // Comparison with T
template< typename T, typename U > template< typename T, typename U >
inline optional_constexpr bool operator==( optional<T> const & x, U const & v ) optional_nodiscard optional_constexpr bool operator==( optional<T> const & x, U const & v )
{ {
return bool(x) ? *x == v : false; return bool(x) ? *x == v : false;
} }
template< typename T, typename U > template< typename T, typename U >
inline optional_constexpr bool operator==( U const & v, optional<T> const & x ) optional_nodiscard optional_constexpr bool operator==( U const & v, optional<T> const & x )
{ {
return bool(x) ? v == *x : false; return bool(x) ? v == *x : false;
} }
template< typename T, typename U > template< typename T, typename U >
inline optional_constexpr bool operator!=( optional<T> const & x, U const & v ) optional_nodiscard optional_constexpr bool operator!=( optional<T> const & x, U const & v )
{ {
return bool(x) ? *x != v : true; return bool(x) ? *x != v : true;
} }
template< typename T, typename U > template< typename T, typename U >
inline optional_constexpr bool operator!=( U const & v, optional<T> const & x ) optional_nodiscard optional_constexpr bool operator!=( U const & v, optional<T> const & x )
{ {
return bool(x) ? v != *x : true; return bool(x) ? v != *x : true;
} }
template< typename T, typename U > template< typename T, typename U >
inline optional_constexpr bool operator<( optional<T> const & x, U const & v ) optional_nodiscard optional_constexpr bool operator<( optional<T> const & x, U const & v )
{ {
return bool(x) ? *x < v : true; return bool(x) ? *x < v : true;
} }
template< typename T, typename U > template< typename T, typename U >
inline optional_constexpr bool operator<( U const & v, optional<T> const & x ) optional_nodiscard optional_constexpr bool operator<( U const & v, optional<T> const & x )
{ {
return bool(x) ? v < *x : false; return bool(x) ? v < *x : false;
} }
template< typename T, typename U > template< typename T, typename U >
inline optional_constexpr bool operator<=( optional<T> const & x, U const & v ) optional_nodiscard optional_constexpr bool operator<=( optional<T> const & x, U const & v )
{ {
return bool(x) ? *x <= v : true; return bool(x) ? *x <= v : true;
} }
template< typename T, typename U > template< typename T, typename U >
inline optional_constexpr bool operator<=( U const & v, optional<T> const & x ) optional_nodiscard optional_constexpr bool operator<=( U const & v, optional<T> const & x )
{ {
return bool(x) ? v <= *x : false; return bool(x) ? v <= *x : false;
} }
template< typename T, typename U > template< typename T, typename U >
inline optional_constexpr bool operator>( optional<T> const & x, U const & v ) optional_nodiscard optional_constexpr bool operator>( optional<T> const & x, U const & v )
{ {
return bool(x) ? *x > v : false; return bool(x) ? *x > v : false;
} }
template< typename T, typename U > template< typename T, typename U >
inline optional_constexpr bool operator>( U const & v, optional<T> const & x ) optional_nodiscard optional_constexpr bool operator>( U const & v, optional<T> const & x )
{ {
return bool(x) ? v > *x : true; return bool(x) ? v > *x : true;
} }
template< typename T, typename U > template< typename T, typename U >
inline optional_constexpr bool operator>=( optional<T> const & x, U const & v ) optional_nodiscard optional_constexpr bool operator>=( optional<T> const & x, U const & v )
{ {
return bool(x) ? *x >= v : false; return bool(x) ? *x >= v : false;
} }
template< typename T, typename U > template< typename T, typename U >
inline optional_constexpr bool operator>=( U const & v, optional<T> const & x ) optional_nodiscard optional_constexpr bool operator>=( U const & v, optional<T> const & x )
{ {
return bool(x) ? v >= *x : true; return bool(x) ? v >= *x : true;
} }

96
src/syslog.cpp Normal file
View File

@ -0,0 +1,96 @@
/*
ISC License
Copyright (c) 2023, 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.
*/
#include <stdarg.h>
#include <syslog.h>
static bool g_SYSLOG_ENABLED = false;
void
syslog_open()
{
const char *ident = "mergerfs";
const int option = (LOG_CONS|LOG_PID);
const int facility = LOG_USER;
openlog(ident,option,facility);
g_SYSLOG_ENABLED = true;
}
void
syslog_close()
{
closelog();
g_SYSLOG_ENABLED = false;
}
void
syslog_log(const int priority_,
const char *format_,
va_list valist_)
{
if(g_SYSLOG_ENABLED == false)
return;
vsyslog(priority_,format_,valist_);
}
void
syslog_log(const int priority_,
const char *format_,
...)
{
va_list valist;
va_start(valist,format_);
syslog_log(priority_,format_,valist);
va_end(valist);
}
void
syslog_info(const char *format_,
...)
{
va_list valist;
va_start(valist,format_);
syslog_log(LOG_INFO,format_,valist);
va_end(valist);
}
void
syslog_warning(const char *format_,
...)
{
va_list valist;
va_start(valist,format_);
syslog_log(LOG_WARNING,format_,valist);
va_end(valist);
}
void
syslog_error(const char *format_,
...)
{
va_list valist;
va_start(valist,format_);
syslog_log(LOG_ERR,format_,valist);
va_end(valist);
}

29
src/syslog.hpp Normal file
View File

@ -0,0 +1,29 @@
/*
ISC License
Copyright (c) 2023, 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.
*/
#pragma once
#include <syslog.h>
void syslog_open();
void syslog_log(const int priority, const char *format, ...);
void syslog_info(const char *format, ...);
void syslog_warning(const char *format, ...);
void syslog_error(const char *format, ...);
void syslog_close();