From 9c0c68d433fa32614362b2277008d2c5626c91f6 Mon Sep 17 00:00:00 2001 From: Shannon Weyrick Date: Mon, 12 Apr 2021 14:35:23 -0400 Subject: [PATCH] adoption to daemonize, log to file and syslog --- cmd/pktvisord/main.cpp | 105 +++++++++++++++++++++++++++++++++++++---- src/HttpServer.h | 8 ++-- 2 files changed, 101 insertions(+), 12 deletions(-) diff --git a/cmd/pktvisord/main.cpp b/cmd/pktvisord/main.cpp index 6e8bf2b27..f9cb46779 100644 --- a/cmd/pktvisord/main.cpp +++ b/cmd/pktvisord/main.cpp @@ -11,7 +11,9 @@ #include "visor_config.h" #include #include +#include #include +#include #include #include "GeoDB.h" @@ -38,12 +40,16 @@ static const char USAGE[] = --admin-api Enable admin REST API giving complete control plane functionality [default: false] When not specified, the exposed API is read-only access to summarized metrics. When specified, write access is enabled for all modules. + -d Daemonize; fork and continue running in the background [default: false] -h --help Show this screen -v Verbose log output --no-track Don't send lightweight, anonymous usage metrics. --version Show version - --geo-city FILE GeoLite2 City database to use for IP to Geo mapping (if enabled) - --geo-asn FILE GeoLite2 ASN database to use for IP to ASN mapping (if enabled) + --geo-city FILE GeoLite2 City database to use for IP to Geo mapping + --geo-asn FILE GeoLite2 ASN database to use for IP to ASN mapping + Logging Options: + --log-file FILE Log to the given output file name + --syslog Log to syslog Prometheus Options: --prometheus Enable native Prometheus metrics at path /metrics --prom-instance ID Optionally set the 'instance' tag to ID @@ -77,6 +83,70 @@ void initialize_geo(const docopt::value &city, const docopt::value &asn) } } +// adapted from LPI becomeDaemon() +int daemonize() +{ + switch (fork()) { + case -1: + return -1; + case 0: + // Child falls through... + break; + default: + // while parent terminates + _exit(EXIT_SUCCESS); + } + + // Become leader of new session + if (setsid() == -1) { + return -1; + } + + // Ensure we are not session leader + switch (auto pid = fork()) { + case -1: + return -1; + case 0: + break; + default: + std::cerr << "pktvisord running at PID " << pid << std::endl; + _exit(EXIT_SUCCESS); + } + + // Clear file mode creation mask + umask(0); + + // Change to root directory + chdir("/"); + int maxfd, fd; + maxfd = sysconf(_SC_OPEN_MAX); + // Limit is indeterminate... + if (maxfd == -1) { + maxfd = 8192; // so take a guess + } + + for (fd = 0; fd < maxfd; fd++) { + close(fd); + } + + // Reopen standard fd's to /dev/null + close(STDIN_FILENO); + + fd = open("/dev/null", O_RDWR); + + if (fd != STDIN_FILENO) { + return -1; + } + if (dup2(STDIN_FILENO, STDOUT_FILENO) != STDOUT_FILENO) { + return -1; + } + if (dup2(STDIN_FILENO, STDERR_FILENO) != STDERR_FILENO) { + return -1; + } + + return 0; +} + int main(int argc, char *argv[]) { @@ -85,7 +155,26 @@ int main(int argc, char *argv[]) true, // show help if requested VISOR_VERSION); // version string - auto logger = spdlog::stdout_color_mt("pktvisor"); + if (args["-d"].asBool()) { + if (daemonize()) { + std::cerr << "failed to daemonize" << std::endl; + exit(EXIT_FAILURE); + } + } + + std::shared_ptr logger; + if (args["--log-file"]) { + try { + logger = spdlog::basic_logger_mt("pktvisor", args["--log-file"].asString()); + } catch (const spdlog::spdlog_ex &ex) { + std::cerr << "Log init failed: " << ex.what() << std::endl; + exit(EXIT_FAILURE); + } + } else if (args["--syslog"].asBool()) { + logger = spdlog::syslog_logger_mt("pktvisor", "pktvisord", LOG_PID); + } else { + logger = spdlog::stdout_color_mt("pktvisor"); + } if (args["-v"].asBool()) { logger->set_level(spdlog::level::debug); } @@ -151,7 +240,7 @@ int main(int argc, char *argv[]) initialize_geo(args["--geo-city"], args["--geo-asn"]); } catch (const std::exception &e) { logger->error("Fatal error: {}", e.what()); - exit(-1); + exit(EXIT_FAILURE); } if (args["IFACE"]) { @@ -195,21 +284,21 @@ int main(int argc, char *argv[]) } catch (const std::exception &e) { logger->error(e.what()); - exit(-1); + exit(EXIT_FAILURE); } } else if (!args["--admin-api"].asBool()) { // if they didn't specify pcap target, or config file, or admin api then there is nothing to do logger->error("Nothing to do: specify --admin-api or IFACE."); std::cerr << USAGE << std::endl; - exit(-1); + exit(EXIT_FAILURE); } try { svr.start(host.c_str(), port); } catch (const std::exception &e) { logger->error(e.what()); - exit(-1); + exit(EXIT_FAILURE); } - return 0; + exit(EXIT_SUCCESS); } diff --git a/src/HttpServer.h b/src/HttpServer.h index b3a7bee8e..b890818da 100644 --- a/src/HttpServer.h +++ b/src/HttpServer.h @@ -20,7 +20,7 @@ class HttpServer : public httplib::Server Server &Get(const char *pattern, Handler handler) { - spdlog::info("Registering GET {}", pattern); + spdlog::get("pktvisor")->info("Registering GET {}", pattern); return httplib::Server::Get(pattern, handler); } Server &Post(const char *pattern, Handler handler) @@ -28,7 +28,7 @@ class HttpServer : public httplib::Server if (_read_only) { return *this; } - spdlog::info("Registering POST {}", pattern); + spdlog::get("pktvisor")->info("Registering POST {}", pattern); return httplib::Server::Post(pattern, handler); } Server &Put(const char *pattern, Handler handler) @@ -36,7 +36,7 @@ class HttpServer : public httplib::Server if (_read_only) { return *this; } - spdlog::info("Registering PUT {}", pattern); + spdlog::get("pktvisor")->info("Registering PUT {}", pattern); return httplib::Server::Put(pattern, handler); } Server &Delete(const char *pattern, Handler handler) @@ -44,7 +44,7 @@ class HttpServer : public httplib::Server if (_read_only) { return *this; } - spdlog::info("Registering DELETE {}", pattern); + spdlog::get("pktvisor")->info("Registering DELETE {}", pattern); return httplib::Server::Delete(pattern, handler); } };