From 5f2614336cce39c01854b67410cc3d6c53bd1904 Mon Sep 17 00:00:00 2001 From: Alberto Miranda Date: Mon, 3 Jul 2023 12:54:07 +0200 Subject: [PATCH] scord-ctl: Write pidfiles on demand --- src/common/net/server.cpp | 86 +++++++++++++++++++++--------------- src/common/net/server.hpp | 3 +- src/scord-ctl/rpc_server.cpp | 5 ++- src/scord-ctl/rpc_server.hpp | 3 +- src/scord-ctl/scord_ctl.cpp | 7 ++- 5 files changed, 63 insertions(+), 41 deletions(-) diff --git a/src/common/net/server.cpp b/src/common/net/server.cpp index 27ddbf24..a11d3a15 100644 --- a/src/common/net/server.cpp +++ b/src/common/net/server.cpp @@ -44,14 +44,51 @@ using namespace std::literals; +namespace { +void +write_pidfile(const std::filesystem::path& pidfile) { + + int fd; + + if((fd = ::open(pidfile.c_str(), O_RDWR | O_CREAT, 0640)) == -1) { + throw std::system_error(errno, std::system_category(), + "Failed to create daemon lock file"); + } + + if(::lockf(fd, F_TLOCK, 0) < 0) { + throw std::system_error(errno, std::system_category(), + "Failed to acquire lock on pidfile. Another " + "instance of this daemon may already be " + "running"); + } + + /* record pid in lockfile */ + std::string pidstr(std::to_string(getpid())); + + if(::write(fd, pidstr.c_str(), pidstr.length()) != + static_cast(pidstr.length())) { + throw std::system_error(errno, std::system_category(), + "Failed to write pidfile"); + } + + /* flush changes */ + ::fsync(fd); + ::fdatasync(fd); + + ::close(fd); +} +} // namespace + namespace network { server::server(std::string name, std::string address, bool daemonize, - std::filesystem::path rundir) + std::filesystem::path rundir, + std::optional pidfile) + : m_name(std::move(name)), m_address(std::move(address)), m_daemonize(daemonize), m_rundir(std::move(rundir)), m_pidfile(daemonize ? std::make_optional(m_rundir / (m_name + ".pid")) - : std::nullopt), + : std::move(pidfile)), m_logger_config(m_name, logger::logger_type::console_color), m_network_engine(m_address, THALLIUM_SERVER_MODE) {} @@ -150,39 +187,6 @@ server::daemonize() { exit(EXIT_FAILURE); } - /* Check if daemon already exists: - * First instance of the daemon will lock the file so that other - * instances understand that an instance is already running. - */ - int pfd; - - if(!m_pidfile.has_value()) { - LOGGER_ERROR("Daemon lock file not specified"); - exit(EXIT_FAILURE); - } - - if((pfd = ::open(m_pidfile->string().c_str(), O_RDWR | O_CREAT, 0640)) == - -1) { - LOGGER_ERRNO("Failed to create daemon lock file"); - exit(EXIT_FAILURE); - } - - if(::lockf(pfd, F_TLOCK, 0) < 0) { - LOGGER_ERRNO("Failed to acquire lock on pidfile"); - LOGGER_ERROR("Another instance of this daemon may already be running"); - exit(EXIT_FAILURE); - } - - /* record pid in lockfile */ - std::string pidstr(std::to_string(getpid())); - - if(::write(pfd, pidstr.c_str(), pidstr.length()) != - static_cast(pidstr.length())) { - LOGGER_ERRNO("Failed to write pidfile"); - exit(EXIT_FAILURE); - } - - ::close(pfd); ::close(dev_null); /* Manage signals */ @@ -324,6 +328,16 @@ server::run() { return EXIT_SUCCESS; } + // write pidfile if needed + if(m_pidfile.has_value()) { + try { + ::write_pidfile(m_pidfile.value()); + } catch(const std::system_error& e) { + LOGGER_ERROR("Failed to create pidfile: {}", e.what()); + return EXIT_FAILURE; + } + } + // print useful information print_greeting(); print_configuration(); @@ -354,7 +368,7 @@ server::teardown() { LOGGER_INFO("* Stopping signal listener..."); m_signal_listener.stop(); - if(!m_daemonize || !m_pidfile) { + if(!m_daemonize) { return; } diff --git a/src/common/net/server.hpp b/src/common/net/server.hpp index 7f577469..267ac598 100644 --- a/src/common/net/server.hpp +++ b/src/common/net/server.hpp @@ -46,7 +46,8 @@ class server { public: server(std::string name, std::string address, bool daemonize, - std::filesystem::path rundir); + std::filesystem::path rundir, + std::optional pidfile = {}); ~server(); diff --git a/src/scord-ctl/rpc_server.cpp b/src/scord-ctl/rpc_server.cpp index 442be085..177104f5 100644 --- a/src/scord-ctl/rpc_server.cpp +++ b/src/scord-ctl/rpc_server.cpp @@ -34,9 +34,10 @@ using namespace std::literals; namespace scord_ctl { rpc_server::rpc_server(std::string name, std::string address, bool daemonize, - std::filesystem::path rundir) + std::filesystem::path rundir, + std::optional pidfile) : server::server(std::move(name), std::move(address), std::move(daemonize), - std::move(rundir)), + std::move(rundir), std::move(pidfile)), provider::provider(m_network_engine, 0) { #define EXPAND(rpc_name) "ADM_" #rpc_name##s, &rpc_server::rpc_name diff --git a/src/scord-ctl/rpc_server.hpp b/src/scord-ctl/rpc_server.hpp index ca617eb1..fa0518b4 100644 --- a/src/scord-ctl/rpc_server.hpp +++ b/src/scord-ctl/rpc_server.hpp @@ -37,7 +37,8 @@ class rpc_server : public network::server, public: rpc_server(std::string name, std::string address, bool daemonize, - std::filesystem::path rundir); + std::filesystem::path rundir, + std::optional pidfile = {}); void set_config(std::optional config); diff --git a/src/scord-ctl/scord_ctl.cpp b/src/scord-ctl/scord_ctl.cpp index aa485074..27de4b21 100644 --- a/src/scord-ctl/scord_ctl.cpp +++ b/src/scord-ctl/scord_ctl.cpp @@ -46,6 +46,7 @@ main(int argc, char* argv[]) { struct { std::optional output_file; std::string address; + std::optional pidfile; } cli_args; const auto progname = fs::path{argv[0]}.filename().string(); @@ -67,6 +68,10 @@ main(int argc, char* argv[]) { ->option_text("ADDRESS") ->required(); + app.add_option("-p,--pidfile", cli_args.pidfile, + "Write the daemon's PID to FILENAME") + ->option_text("FILENAME"); + app.set_config("-c,--config-file", scord_ctl::config::defaults::config_file, "Ignore the system-wide configuration file and use the " "configuration provided by FILENAME", @@ -91,7 +96,7 @@ main(int argc, char* argv[]) { app.get_config_ptr()->as()); scord_ctl::rpc_server srv(progname, cli_args.address, false, - fs::current_path()); + fs::current_path(), cli_args.pidfile); if(cli_args.output_file) { srv.configure_logger(logger::logger_type::file, *cli_args.output_file); -- GitLab