Add option to wait for branches to become new mounts

branches-mount-timeout=UINT64 in seconds (default: 0)
This commit is contained in:
Antonio SJ Musumeci 2022-12-30 18:03:13 -05:00
parent 2d8d0f7ad6
commit 939eb3996a
14 changed files with 3034 additions and 106 deletions

View File

@ -1,7 +1,7 @@
/*
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
purpose with or without fee is hereby granted, provided that the above

View File

@ -1,6 +1,6 @@
% mergerfs(1) mergerfs user manual
% Antonio SJ Musumeci <trapexit@spawn.link>
% 2023-01-16
% 2023-01-24
# 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
over NFS where there are issues with creating files for write while
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
what they point to. (default: never)
* **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
Branches::from_string(const std::string &str_)
{

View File

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

View File

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

View File

@ -103,6 +103,7 @@ public:
ConfigBOOL auto_cache;
ConfigUINT64 minfreespace;
Branches branches;
ConfigUINT64 branches_mount_timeout;
ConfigUINT64 cache_attr;
ConfigUINT64 cache_entry;
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.
*/
#include "fs_wait_for_mount.hpp"
#include "syslog.hpp"
#include "fs_path.hpp"
#include "mergerfs.hpp"
#include "option_parser.hpp"
@ -147,6 +150,33 @@ namespace l
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
main(const int argc_,
char **argv_)
@ -156,6 +186,8 @@ namespace l
fuse_args args;
fuse_operations ops;
syslog_open();
memset(&ops,0,sizeof(fuse_operations));
args.argc = argc_;
@ -169,6 +201,9 @@ namespace l
return 1;
}
if(cfg->branches_mount_timeout > 0)
l::wait_for_mount(cfg);
l::setup_resources();
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 )
#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):
#ifndef optional_CONFIG_NO_EXCEPTIONS
# if defined(_MSC_VER)
# include <cstddef> // for _HAS_EXCEPTIONS
# 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
# else
# define optional_CONFIG_NO_EXCEPTIONS 1
# 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.
#ifndef optional_CPLUSPLUS
@ -73,7 +79,8 @@
#define optional_CPP11_OR_GREATER_ ( optional_CPLUSPLUS >= 201103L )
#define optional_CPP14_OR_GREATER ( optional_CPLUSPLUS >= 201402L )
#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):
@ -782,7 +789,7 @@ union storage_t
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 >
@ -794,13 +801,13 @@ union storage_t
template< class... 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 >
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
@ -1485,7 +1492,40 @@ public:
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
@ -1530,37 +1570,37 @@ private:
// Relational operators
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;
}
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);
}
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;
}
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);
}
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);
}
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);
}
@ -1568,73 +1608,73 @@ inline optional_constexpr bool operator>=( optional<T> const & x, optional<U> co
// Comparison with nullopt
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);
}
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);
}
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);
}
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);
}
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;
}
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);
}
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);
}
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;
}
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);
}
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;
}
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;
}
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);
}
@ -1642,73 +1682,73 @@ inline optional_constexpr bool operator>=( nullopt_t /*unused*/, optional<T> con
// Comparison with T
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}

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();