diff --git a/userspace/falco/app_actions/create_signal_handlers.cpp b/userspace/falco/app_actions/create_signal_handlers.cpp index b1f87e15..f0d4248c 100644 --- a/userspace/falco/app_actions/create_signal_handlers.cpp +++ b/userspace/falco/app_actions/create_signal_handlers.cpp @@ -18,6 +18,8 @@ limitations under the License. #include #include +#include +#include #include "application.h" @@ -30,6 +32,7 @@ using namespace falco::app; static application dummy; static std::reference_wrapper s_app = dummy; +static int inot_fd; static void signal_callback(int signal) { @@ -85,10 +88,87 @@ application::run_result application::create_signal_handlers() return ret; } +application::run_result application::attach_inotify_signals() +{ + run_result ret; + if (m_options.monitor_files) + { + inot_fd = inotify_init(); + if (inot_fd == -1) + { + ret.success = false; + ret.errstr = std::string("Could not create inotify handler."); + ret.proceed = false; + return ret; + } + + struct sigaction sa; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + sa.sa_handler = restart_falco; + if (sigaction(SIGIO, &sa, NULL) == -1) + { + ret.success = false; + ret.errstr = std::string("Failed to link SIGIO to inotify handler."); + ret.proceed = false; + return ret; + } + + /* Set owner process that is to receive "I/O possible" signal */ + if (fcntl(inot_fd, F_SETOWN, getpid()) == -1) + { + ret.success = false; + ret.errstr = std::string("Failed to setting owner on inotify handler."); + ret.proceed = false; + return ret; + } + + /* + * Enable "I/O possible" signaling and make I/O nonblocking + * for file descriptor + */ + int flags = fcntl(inot_fd, F_GETFL); + if (fcntl(inot_fd, F_SETFL, flags | O_ASYNC | O_NONBLOCK) == -1) + { + ret.success = false; + ret.errstr = std::string("Failed to setting flags on inotify handler."); + ret.proceed = false; + return ret; + } + + /* Add watchers */ + int wd = inotify_add_watch(inot_fd, m_options.conf_filename.c_str(), IN_CLOSE_WRITE); + if (wd == -1) + { + ret.success = false; + ret.errstr = std::string("Failed to watch conf file."); + ret.proceed = false; + return ret; + } + falco_logger::log(LOG_DEBUG, "Watching " + m_options.conf_filename +"\n"); + + for (const auto &rule : m_state->config->m_rules_filenames) { + wd = inotify_add_watch(inot_fd, rule.c_str(), IN_CLOSE_WRITE); + if (wd == -1) + { + ret.success = false; + ret.errstr = std::string("Failed to watch rule file: ") + rule; + ret.proceed = false; + return ret; + } + falco_logger::log(LOG_DEBUG, "Watching " + rule +"\n"); + } + } + + return ret; +} + bool application::unregister_signal_handlers(std::string &errstr) { run_result ret; + close(inot_fd); + if(! create_handler(SIGINT, SIG_DFL, ret) || ! create_handler(SIGTERM, SIG_DFL, ret) || ! create_handler(SIGUSR1, SIG_DFL, ret) || diff --git a/userspace/falco/app_actions/load_config.cpp b/userspace/falco/app_actions/load_config.cpp index bf7ce6c6..574d0ba8 100644 --- a/userspace/falco/app_actions/load_config.cpp +++ b/userspace/falco/app_actions/load_config.cpp @@ -22,7 +22,7 @@ application::run_result application::load_config() { run_result ret; - if (m_options.conf_filename.size()) + if (!m_options.conf_filename.empty()) { m_state->config->init(m_options.conf_filename, m_options.cmdline_config_options); falco_logger::set_time_format_iso_8601(m_state->config->m_time_format_iso_8601); diff --git a/userspace/falco/app_actions/load_rules_files.cpp b/userspace/falco/app_actions/load_rules_files.cpp index bffea17c..b3495e6f 100644 --- a/userspace/falco/app_actions/load_rules_files.cpp +++ b/userspace/falco/app_actions/load_rules_files.cpp @@ -72,12 +72,12 @@ application::run_result application::load_rules_files() string all_rules; - if (m_options.rules_filenames.size()) + if (!m_options.rules_filenames.empty()) { m_state->config->m_rules_filenames = m_options.rules_filenames; } - if(m_state->config->m_rules_filenames.size() == 0) + if(m_state->config->m_rules_filenames.empty()) { ret.success = false; ret.errstr = "You must specify at least one rules file/directory via -r or a rules_file entry in falco.yaml"; diff --git a/userspace/falco/app_cmdline_options.cpp b/userspace/falco/app_cmdline_options.cpp index 4855305b..f278636c 100644 --- a/userspace/falco/app_cmdline_options.cpp +++ b/userspace/falco/app_cmdline_options.cpp @@ -181,6 +181,7 @@ void cmdline_options::define() #endif ("M", "Stop collecting after reached.", cxxopts::value(duration_to_tot)->default_value("0"), "") ("markdown", "When used with --list/--list-syscall-events, print the content in Markdown format", cxxopts::value(markdown)) + ("monitor_files", "Monitor rules and config files to reload Falco on change.", cxxopts::value(monitor_files)) ("N", "When used with --list, only print field names.", cxxopts::value(names_only)->default_value("false")) ("o,option", "Set the value of option to . Overrides values in configuration file. can be identified using its location in configuration file using dot notation. Elements which are entries of lists can be accessed via square brackets [].\n E.g. base.id = val\n base.subvalue.subvalue2 = val\n base.list[1]=val", cxxopts::value(cmdline_config_options), "=") ("p,print", "Add additional information to each falco notification's output.\nWith -pc or -pcontainer will use a container-friendly format.\nWith -pk or -pkubernetes will use a kubernetes-friendly format.\nWith -pm or -pmesos will use a mesos-friendly format.\nAdditionally, specifying -pc/-pk/-pm will change the interpretation of %container.info in rule output fields.", cxxopts::value(print_additional), "") diff --git a/userspace/falco/app_cmdline_options.h b/userspace/falco/app_cmdline_options.h index 240356ff..c774f89e 100644 --- a/userspace/falco/app_cmdline_options.h +++ b/userspace/falco/app_cmdline_options.h @@ -35,6 +35,7 @@ public: // Each of these maps directly to a command line option. bool help; std::string conf_filename; + bool monitor_files; bool all_events; sinsp_evt::param_fmt event_buffer_format; std::vector cri_socket_paths; diff --git a/userspace/falco/application.cpp b/userspace/falco/application.cpp index 37423a43..3d7f49be 100644 --- a/userspace/falco/application.cpp +++ b/userspace/falco/application.cpp @@ -138,6 +138,7 @@ bool application::run(std::string &errstr, bool &restart) std::bind(&application::print_ignored_events, this), std::bind(&application::print_support, this), std::bind(&application::validate_rules_files, this), + std::bind(&application::attach_inotify_signals, this), std::bind(&application::daemonize, this), std::bind(&application::init_outputs, this), std::bind(&application::open_inspector, this), diff --git a/userspace/falco/application.h b/userspace/falco/application.h index 1a3f17d4..33532284 100644 --- a/userspace/falco/application.h +++ b/userspace/falco/application.h @@ -125,6 +125,7 @@ private: // These methods comprise the code the application "runs". The // order in which the methods run is in application.cpp. run_result create_signal_handlers(); + run_result attach_inotify_signals(); run_result daemonize(); run_result init_falco_engine(); run_result init_inspector();