Browse Source

Merge pull request #1123 from trapexit/wait

Add option to wait for branches to become new mounts
pull/1125/head
trapexit 2 years ago
committed by GitHub
parent
commit
16e9ba2f19
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      LICENSE
  2. 5
      README.md
  3. 11
      src/branches.cpp
  4. 3
      src/branches.hpp
  5. 135
      src/config.cpp
  6. 1
      src/config.hpp
  7. 10
      src/fs_pathvector.hpp
  8. 112
      src/fs_wait_for_mount.cpp
  9. 50
      src/fs_wait_for_mount.hpp
  10. 35
      src/mergerfs.cpp
  11. 2537
      src/nonstd/expected.hpp
  12. 114
      src/nonstd/optional.hpp
  13. 96
      src/syslog.cpp
  14. 29
      src/syslog.hpp

2
LICENSE

@ -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

5
README.md

@ -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**:

11
src/branches.cpp

@ -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_)
{

3
src/branches.hpp

@ -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_);

135
src/config.cpp

@ -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&

1
src/config.hpp

@ -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

@ -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

@ -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

@ -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);
}

35
src/mergerfs.cpp

@ -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
File diff suppressed because it is too large
View File

114
src/nonstd/optional.hpp

@ -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

@ -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

@ -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();
Loading…
Cancel
Save