sys: Log to a file when ImHex wasn't opened though a terminal

This commit is contained in:
WerWolv 2022-01-17 20:06:00 +01:00
parent 2df4e22bf8
commit 8701e0f402
15 changed files with 155 additions and 42 deletions

View File

@ -9,5 +9,12 @@
<mapping directory="$PROJECT_DIR$/external/nativefiledialog" vcs="Git" /> <mapping directory="$PROJECT_DIR$/external/nativefiledialog" vcs="Git" />
<mapping directory="$PROJECT_DIR$/external/xdgpp" vcs="Git" /> <mapping directory="$PROJECT_DIR$/external/xdgpp" vcs="Git" />
<mapping directory="$PROJECT_DIR$/external/yara/yara" vcs="Git" /> <mapping directory="$PROJECT_DIR$/external/yara/yara" vcs="Git" />
<mapping directory="$PROJECT_DIR$/lib/external/capstone" vcs="Git" />
<mapping directory="$PROJECT_DIR$/lib/external/curl" vcs="Git" />
<mapping directory="$PROJECT_DIR$/lib/external/fmt" vcs="Git" />
<mapping directory="$PROJECT_DIR$/lib/external/libromfs" vcs="Git" />
<mapping directory="$PROJECT_DIR$/lib/external/nativefiledialog" vcs="Git" />
<mapping directory="$PROJECT_DIR$/lib/external/xdgpp" vcs="Git" />
<mapping directory="$PROJECT_DIR$/lib/external/yara/yara" vcs="Git" />
</component> </component>
</project> </project>

View File

@ -123,6 +123,7 @@ set(LIBIMHEX_SOURCES
source/helpers/project_file_handler.cpp source/helpers/project_file_handler.cpp
source/helpers/encoding_file.cpp source/helpers/encoding_file.cpp
source/helpers/loader_script_handler.cpp source/helpers/loader_script_handler.cpp
source/helpers/logger.cpp
source/pattern_language/pattern_language.cpp source/pattern_language/pattern_language.cpp
source/pattern_language/preprocessor.cpp source/pattern_language/preprocessor.cpp

View File

@ -26,13 +26,16 @@ namespace hex {
Create Create
}; };
explicit File(const fs::path &path, Mode mode); explicit File(const fs::path &path, Mode mode) noexcept;
File(); File() noexcept;
File(const File&) = delete; File(const File&) = delete;
File(File &&other) noexcept; File(File &&other) noexcept;
~File(); ~File();
File& operator=(File &&other) noexcept;
[[nodiscard]] bool isValid() const { return this->m_file != nullptr; } [[nodiscard]] bool isValid() const { return this->m_file != nullptr; }
void seek(u64 offset); void seek(u64 offset);

View File

@ -5,36 +5,54 @@
namespace hex::log { namespace hex::log {
FILE *getDestination();
bool isRedirected();
template <typename... T>
void print(fmt::format_string<T...> fmt, T&&... args) {
fmt::print(getDestination(), fmt, args...);
}
template <typename S, typename... Args>
void print(const fmt::text_style& ts, const S& fmt, const Args&... args) {
if (isRedirected())
fmt::print(getDestination(), fmt::runtime(fmt), args...);
else
fmt::print(getDestination(), ts, fmt, args...);
}
void debug(const std::string &fmt, auto ... args) { void debug(const std::string &fmt, auto ... args) {
#if defined(DEBUG) #if defined(DEBUG)
fmt::print(fg(fmt::color::green_yellow) | fmt::emphasis::bold, "[DEBUG] "); log::print(fg(fmt::color::green_yellow) | fmt::emphasis::bold, "[DEBUG] ");
fmt::print(fmt::runtime(fmt), args...); log::print(fmt::runtime(fmt), args...);
fmt::print("\n"); log::print("\n");
#endif #endif
} }
void info(const std::string &fmt, auto ... args) { void info(const std::string &fmt, auto ... args) {
fmt::print(fg(fmt::color::cadet_blue) | fmt::emphasis::bold, "[INFO] "); log::print(fg(fmt::color::cadet_blue) | fmt::emphasis::bold, "[INFO] ");
fmt::print(fmt::runtime(fmt), args...); log::print(fmt::runtime(fmt), args...);
fmt::print("\n"); log::print("\n");
} }
void warn(const std::string &fmt, auto ... args) { void warn(const std::string &fmt, auto ... args) {
fmt::print(fg(fmt::color::orange) | fmt::emphasis::bold, "[WARN] "); log::print(fg(fmt::color::orange) | fmt::emphasis::bold, "[WARN] ");
fmt::print(fmt::runtime(fmt), args...); log::print(fmt::runtime(fmt), args...);
fmt::print("\n"); log::print("\n");
} }
void error(const std::string &fmt, auto ... args) { void error(const std::string &fmt, auto ... args) {
fmt::print(fg(fmt::color::red) | fmt::emphasis::bold, "[ERROR] "); log::print(fg(fmt::color::red) | fmt::emphasis::bold, "[ERROR] ");
fmt::print(fmt::runtime(fmt), args...); log::print(fmt::runtime(fmt), args...);
fmt::print("\n"); log::print("\n");
} }
void fatal(const std::string &fmt, auto ... args) { void fatal(const std::string &fmt, auto ... args) {
fmt::print(fg(fmt::color::purple) | fmt::emphasis::bold, "[FATAL] "); log::print(fg(fmt::color::purple) | fmt::emphasis::bold, "[FATAL] ");
fmt::print(fmt::runtime(fmt), args...); log::print(fmt::runtime(fmt), args...);
fmt::print("\n"); log::print("\n");
} }
void redirectToFile();
} }

View File

@ -17,7 +17,8 @@ namespace hex {
Yara, Yara,
Config, Config,
Resources, Resources,
Constants Constants,
Logs
}; };
std::string getExecutablePath(); std::string getExecutablePath();

View File

@ -3,7 +3,7 @@
namespace hex { namespace hex {
File::File(const fs::path &path, Mode mode) : m_path(path) { File::File(const fs::path &path, Mode mode) noexcept : m_path(path) {
if (mode == File::Mode::Read) if (mode == File::Mode::Read)
this->m_file = fopen64(path.string().c_str(), "rb"); this->m_file = fopen64(path.string().c_str(), "rb");
else if (mode == File::Mode::Write) else if (mode == File::Mode::Write)
@ -13,7 +13,7 @@ namespace hex {
this->m_file = fopen64(path.string().c_str(), "w+b"); this->m_file = fopen64(path.string().c_str(), "w+b");
} }
File::File() { File::File() noexcept {
this->m_file = nullptr; this->m_file = nullptr;
} }
@ -26,6 +26,16 @@ namespace hex {
this->close(); this->close();
} }
File& File::operator=(File &&other) noexcept {
this->m_file = other.m_file;
other.m_file = nullptr;
this->m_path = std::move(other.m_path);
return *this;
}
void File::seek(u64 offset) { void File::seek(u64 offset) {
fseeko64(this->m_file, offset, SEEK_SET); fseeko64(this->m_file, offset, SEEK_SET);
} }

View File

@ -0,0 +1,33 @@
#include <hex/helpers/logger.hpp>
#include <hex/helpers/file.hpp>
#include <hex/helpers/paths.hpp>
#include <hex/helpers/fmt.hpp>
#include <iostream>
namespace hex::log {
static File g_loggerFile;
FILE* getDestination() {
if (g_loggerFile.isValid())
return g_loggerFile.getHandle();
else
return stdout;
}
bool isRedirected() {
return g_loggerFile.isValid();
}
void redirectToFile() {
if (g_loggerFile.isValid()) return;
for (const auto &path : hex::getPath(ImHexPath::Logs)) {
g_loggerFile = File(path / hex::format("{0:%Y%m%d_%H%M%S}.log", fmt::localtime(std::chrono::system_clock::now())), File::Mode::Create);
if (g_loggerFile.isValid()) break;
}
}
}

View File

@ -98,6 +98,11 @@ namespace hex {
return (path / "constants").string(); return (path / "constants").string();
}); });
break; break;
case ImHexPath::Logs:
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path){
return (path / "logs").string();
});
break;
default: __builtin_unreachable(); default: __builtin_unreachable();
} }
#elif defined(OS_MACOS) #elif defined(OS_MACOS)
@ -137,6 +142,9 @@ namespace hex {
case ImHexPath::Constants: case ImHexPath::Constants:
result.push_back((applicationSupportDir / "constants").string()); result.push_back((applicationSupportDir / "constants").string());
break; break;
case ImHexPath::Logs:
result.push_back((applicationSupportDir / "logs").string());
break;
default: __builtin_unreachable(); default: __builtin_unreachable();
} }
#else #else
@ -191,6 +199,10 @@ namespace hex {
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result),
[](auto p) { return (p / "constants").string(); }); [](auto p) { return (p / "constants").string(); });
break; break;
case ImHexPath::Logs:
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result),
[](auto p) { return (p / "logs").string(); });
break;
default: __builtin_unreachable(); default: __builtin_unreachable();
} }
#endif #endif

View File

@ -16,17 +16,18 @@ namespace hex {
class Plugin { class Plugin {
public: public:
Plugin(const fs::path &path); explicit Plugin(const fs::path &path);
Plugin(const Plugin&) = delete; Plugin(const Plugin&) = delete;
Plugin(Plugin &&other) noexcept; Plugin(Plugin &&other) noexcept;
~Plugin(); ~Plugin();
void initializePlugin() const; [[nodiscard]] bool initializePlugin() const;
[[nodiscard]] std::string getPluginName() const; [[nodiscard]] std::string getPluginName() const;
[[nodiscard]] std::string getPluginAuthor() const; [[nodiscard]] std::string getPluginAuthor() const;
[[nodiscard]] std::string getPluginDescription() const; [[nodiscard]] std::string getPluginDescription() const;
void setImGuiContext(ImGuiContext *ctx) const; void setImGuiContext(ImGuiContext *ctx) const;
[[nodiscard]] const fs::path& getPath() const;
private: private:
using InitializePluginFunc = void(*)(); using InitializePluginFunc = void(*)();
@ -36,6 +37,7 @@ namespace hex {
using SetImGuiContextFunc = void(*)(ImGuiContext*); using SetImGuiContextFunc = void(*)(ImGuiContext*);
void *m_handle = nullptr; void *m_handle = nullptr;
fs::path m_path;
InitializePluginFunc m_initializePluginFunction = nullptr; InitializePluginFunc m_initializePluginFunction = nullptr;
GetPluginNameFunc m_getPluginNameFunction = nullptr; GetPluginNameFunc m_getPluginNameFunction = nullptr;

View File

@ -14,7 +14,7 @@ namespace hex {
constexpr auto GetPluginDescriptionSymbol = "_ZN3hex6plugin{0}{1}8internal20getPluginDescriptionEv"; constexpr auto GetPluginDescriptionSymbol = "_ZN3hex6plugin{0}{1}8internal20getPluginDescriptionEv";
constexpr auto SetImGuiContextSymbol = "_ZN3hex6plugin{0}{1}8internal15setImGuiContextEP12ImGuiContext"; constexpr auto SetImGuiContextSymbol = "_ZN3hex6plugin{0}{1}8internal15setImGuiContextEP12ImGuiContext";
Plugin::Plugin(const fs::path &path) { Plugin::Plugin(const fs::path &path) : m_path(path) {
this->m_handle = dlopen(path.string().c_str(), RTLD_LAZY); this->m_handle = dlopen(path.string().c_str(), RTLD_LAZY);
if (this->m_handle == nullptr) { if (this->m_handle == nullptr) {
@ -33,6 +33,8 @@ namespace hex {
Plugin::Plugin(Plugin &&other) noexcept { Plugin::Plugin(Plugin &&other) noexcept {
this->m_handle = other.m_handle; this->m_handle = other.m_handle;
this->m_path = std::move(other.m_path);
this->m_initializePluginFunction = other.m_initializePluginFunction; this->m_initializePluginFunction = other.m_initializePluginFunction;
this->m_getPluginNameFunction = other.m_getPluginNameFunction; this->m_getPluginNameFunction = other.m_getPluginNameFunction;
this->m_getPluginAuthorFunction = other.m_getPluginAuthorFunction; this->m_getPluginAuthorFunction = other.m_getPluginAuthorFunction;
@ -52,9 +54,13 @@ namespace hex {
dlclose(this->m_handle); dlclose(this->m_handle);
} }
void Plugin::initializePlugin() const { bool Plugin::initializePlugin() const {
if (this->m_initializePluginFunction != nullptr) if (this->m_initializePluginFunction != nullptr) {
this->m_initializePluginFunction(); this->m_initializePluginFunction();
return true;
} else {
return false;
}
} }
std::string Plugin::getPluginName() const { std::string Plugin::getPluginName() const {
@ -83,6 +89,12 @@ namespace hex {
this->m_setImGuiContextFunction(ctx); this->m_setImGuiContextFunction(ctx);
} }
const fs::path &Plugin::getPath() const {
return this->m_path;
}
bool PluginManager::load(const fs::path &pluginFolder) { bool PluginManager::load(const fs::path &pluginFolder) {
if (!fs::exists(pluginFolder)) if (!fs::exists(pluginFolder))
return false; return false;

View File

@ -49,7 +49,8 @@ namespace hex::init {
try { try {
status = task() && status; status = task() && status;
} catch (...) { } catch (std::exception &e) {
log::error("Init task {} threw an exception: {}", name, e.what());
status = false; status = false;
} }

View File

@ -57,7 +57,7 @@ namespace hex::init {
bool createDirectories() { bool createDirectories() {
bool result = true; bool result = true;
std::array paths = { constexpr std::array paths = {
ImHexPath::Patterns, ImHexPath::Patterns,
ImHexPath::PatternsInclude, ImHexPath::PatternsInclude,
ImHexPath::Magic, ImHexPath::Magic,
@ -66,7 +66,8 @@ namespace hex::init {
ImHexPath::Config, ImHexPath::Config,
ImHexPath::Constants, ImHexPath::Constants,
ImHexPath::Yara, ImHexPath::Yara,
ImHexPath::Python ImHexPath::Python,
ImHexPath::Logs
}; };
for (auto path : paths) { for (auto path : paths) {
@ -225,7 +226,8 @@ namespace hex::init {
} }
for (const auto &plugin : PluginManager::getPlugins()) { for (const auto &plugin : PluginManager::getPlugins()) {
plugin.initializePlugin(); if (!plugin.initializePlugin())
log::error("Failed to initialize plugin {}", plugin.getPath().filename().string());
} }
return true; return true;

View File

@ -3,13 +3,18 @@
#if defined(OS_LINUX) #if defined(OS_LINUX)
#include <hex/helpers/utils.hpp> #include <hex/helpers/utils.hpp>
#include <hex/helpers/logger.hpp>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <sys/wait.h> #include <sys/wait.h>
#include <unistd.h>
namespace hex { namespace hex {
void Window::initNative() { void Window::initNative() {
if (!isatty(STDOUT_FILENO)) {
log::redirectToFile();
}
} }
void Window::setupNativeWindow() { void Window::setupNativeWindow() {

View File

@ -2,12 +2,17 @@
#if defined(OS_MACOS) #if defined(OS_MACOS)
#include <hex/helpers/logger.hpp>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <unistd.h>
namespace hex { namespace hex {
void Window::initNative() { void Window::initNative() {
if (!isatty(STDOUT_FILENO)) {
log::redirectToFile();
}
} }
void Window::setupNativeWindow() { void Window::setupNativeWindow() {

View File

@ -172,25 +172,26 @@
// Redirect cin, cout and cerr to that console // Redirect cin, cout and cerr to that console
freopen("CONIN$", "r", stdin); freopen("CONIN$", "r", stdin);
freopen("CONOUT$", "w", stdout); freopen("CONOUT$", "w", stdout);
freopen("CONERR$", "w", stderr); freopen("CONOUT$", "w", stderr);
setvbuf(stdin, nullptr, _IONBF, 0); setvbuf(stdin, nullptr, _IONBF, 0);
setvbuf(stdout, nullptr, _IONBF, 0); setvbuf(stdout, nullptr, _IONBF, 0);
setvbuf(stderr, nullptr, _IONBF, 0); setvbuf(stderr, nullptr, _IONBF, 0);
fmt::print("\n"); fmt::print("\n");
}
// Enable color format specifiers in console
// Enable color format specifiers in console {
{ auto hConsole = ::GetStdHandle(STD_OUTPUT_HANDLE);
auto hConsole = ::GetStdHandle(STD_OUTPUT_HANDLE); if (hConsole != INVALID_HANDLE_VALUE) {
if (hConsole != INVALID_HANDLE_VALUE) { DWORD mode = 0;
DWORD mode = 0; if (::GetConsoleMode(hConsole, &mode)) {
if (::GetConsoleMode(hConsole, &mode)) { mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING | ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING | ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT; ::SetConsoleMode(hConsole, mode);
::SetConsoleMode(hConsole, mode); }
} }
} }
} else {
log::redirectToFile();
} }
// Open new files in already existing ImHex instance // Open new files in already existing ImHex instance