2 * Copyright (c) 2014-present, Facebook, Inc.
5 * This source code is licensed in accordance with the terms specified in
6 * the LICENSE file found in the root directory of this source tree.
17 #include <osquery/system.h>
21 #include <osquery/utils/system/system.h>
31 #include <sys/resource.h>
34 #include <boost/filesystem.hpp>
36 #include "osquery/utils/config/default_paths.h"
37 #include "osquery/utils/info/platform_type.h"
38 #include <osquery/core.h>
39 #include <osquery/data_logger.h>
40 #include <osquery/registry.h>
41 #include <osquery/utils/info/version.h>
42 #include <osquery/utils/system/time.h>
45 #include <sys/syscall.h>
48 * These are the io priority groups as implemented by CFQ. RT is the realtime
49 * class, it always gets premium service. BE is the best-effort scheduling
50 * class, the default for any process. IDLE is the idle scheduling class, it
51 * is only served when no one else is using the disk.
61 * 8 best effort priority levels are supported
63 #define IOPRIO_BE_NR (8)
66 IOPRIO_WHO_PROCESS = 1,
73 "osquery %s, your OS as a high-performance relational database\n"
74 #define EPILOG "\nosquery project page <https://osquery.io>.\n"
76 "\nosquery configuration options (set by config or CLI flags):\n\n"
77 #define OPTIONS_SHELL "\nosquery shell-only CLI flags:\n\n"
78 #define OPTIONS_CLI "osquery%s command line flags:\n\n"
79 #define USAGE "Usage: %s [OPTION]... %s\n\n"
83 volatile std::sig_atomic_t kHandledSignal{0};
85 void signalHandler(int num) {
86 // Inform exit status of main threads blocked by service joins.
87 if (kHandledSignal == 0) {
89 // If no part of osquery requested an interruption then the exit 'wanted'
90 // code becomes the signal number.
91 if (num != SIGUSR1 && osquery::kExitCode == 0) {
92 // The only exception is SIGUSR1 which is used to signal the main thread
93 // to interrupt dispatched services.
94 osquery::kExitCode = 128 + num;
97 if (num == SIGTERM || num == SIGINT || num == SIGABRT ||
99 // Restore the default signal handler.
100 std::signal(num, SIG_DFL);
107 using chrono_clock = std::chrono::high_resolution_clock;
109 namespace fs = boost::filesystem;
113 ToolType kToolType{ToolType::UNKNOWN};
115 /// The saved exit code from a thread's request to stop the process.
116 volatile std::sig_atomic_t kExitCode{0};
118 /// The saved thread ID for shutdown to short-circuit raising a signal.
119 static std::thread::id kMainThreadId;
121 /// Legacy thread ID to ensure that the windows service waits before exiting
122 unsigned long kLegacyThreadId;
124 std::function<void()> Initializer::shutdown_{nullptr};
125 RecursiveMutex Initializer::shutdown_mutex_;
127 static inline void printUsage(const std::string& binary, ToolType tool) {
128 // Parse help options before gflags. Only display osquery-related options.
129 fprintf(stdout, DESCRIPTION, kVersion.c_str());
130 if (tool == ToolType::SHELL) {
131 // The shell allows a caller to run a single SQL statement and exit.
132 fprintf(stdout, USAGE, binary.c_str(), "[SQL STATEMENT]");
134 fprintf(stdout, USAGE, binary.c_str(), "");
137 fprintf(stdout, EPILOG);
140 Initializer::Initializer(int& argc,
143 bool const init_glog)
144 : argc_(&argc), argv_(&argv) {
145 // Initialize random number generated based on time.
146 std::srand(static_cast<unsigned int>(
147 chrono_clock::now().time_since_epoch().count()));
149 // osquery can function as the daemon or shell depending on argv[0].
150 if (tool == ToolType::SHELL_DAEMON) {
151 if (fs::path(argv[0]).filename().string().find("osqueryd") !=
153 kToolType = ToolType::DAEMON;
154 binary_ = "osqueryd";
156 kToolType = ToolType::SHELL;
157 binary_ = "osqueryi";
160 // Set the tool type to allow runtime decisions based on daemon, shell, etc.
164 // The 'main' thread is that which executes the initializer.
165 kMainThreadId = std::this_thread::get_id();
167 // Initialize the COM libs
171 void Initializer::initDaemon() const {
174 void Initializer::initShell() const {
177 void Initializer::initWorker(const std::string& name) const {
178 // Clear worker's arguments.
179 auto original_name = std::string((*argv_)[0]);
180 for (int i = 1; i < *argc_; i++) {
181 if ((*argv_)[i] != nullptr) {
182 memset((*argv_)[i], '\0', strlen((*argv_)[i]));
187 void Initializer::initActivePlugin(const std::string& type,
188 const std::string& name) const {
189 auto rs = RegistryFactory::get().setActive(type, name);
191 LOG(ERROR) << "Cannot activate " << name << " " << type
192 << " plugin: " << rs.getMessage();
193 requestShutdown(EXIT_CATASTROPHIC);
197 void Initializer::installShutdown(std::function<void()>& handler) {
198 RecursiveLock lock(shutdown_mutex_);
199 shutdown_ = std::move(handler);
202 void Initializer::start() const {
203 // Run the setup for all lazy registries (tables, SQL).
207 void Initializer::waitForShutdown() {
209 RecursiveLock lock(shutdown_mutex_);
210 if (shutdown_ != nullptr) {
211 // Copy the callable, then remove it, prevent callable recursion.
212 auto shutdown = shutdown_;
215 // Call the shutdown callable.
220 auto excode = (kExitCode != 0) ? kExitCode : EXIT_SUCCESS;
224 void Initializer::requestShutdown(int retcode) {
225 if (kExitCode == 0) {
230 void Initializer::requestShutdown(int retcode, const std::string& system_log) {
231 requestShutdown(retcode);
234 void Initializer::shutdown(int retcode) {