#include "../pchheader.hpp" #include "util.hpp" namespace util { const std::string to_hex(const std::string_view bin) { // Allocate the target string. std::string encoded_string; encoded_string.resize(bin.size() * 2); // Get encoded string. sodium_bin2hex( encoded_string.data(), encoded_string.length() + 1, // + 1 because sodium writes ending '\0' character as well. reinterpret_cast(bin.data()), bin.size()); return encoded_string; } const std::string to_bin(const std::string_view hex) { std::string bin; bin.resize(hex.size() / 2); const char *hex_end; size_t bin_len; if (sodium_hex2bin( reinterpret_cast(bin.data()), bin.size(), hex.data(), hex.size(), "", &bin_len, &hex_end)) { return ""; // Empty indicates error. } return bin; } /** * Check whether given directory exists. * @param path Directory path. * @return Returns true if given directory exists otherwise false. */ bool is_dir_exists(std::string_view path) { struct stat st; return (stat(path.data(), &st) == 0 && S_ISDIR(st.st_mode)); } /** * Check whether given file exists. * @param path File path. * @return Returns true if give file exists otherwise false. */ bool is_file_exists(std::string_view path) { struct stat st; return (stat(path.data(), &st) == 0 && S_ISREG(st.st_mode)); } /** * Recursively creates directories and sub-directories if not exist. * @param path Directory path. * @return Returns 0 operations succeeded otherwise -1. */ int create_dir_tree_recursive(std::string_view path) { if (strcmp(path.data(), "/") == 0) // No need of checking if we are at root. return 0; // Check whether this dir exists or not. struct stat st; if (stat(path.data(), &st) != 0 || !S_ISDIR(st.st_mode)) { // Check and create parent dir tree first. char *path2 = strdup(path.data()); char *parent_dir_path = dirname(path2); bool error_thrown = false; if (create_dir_tree_recursive(parent_dir_path) == -1) error_thrown = true; free(path2); // Create this dir. if (!error_thrown && mkdir(path.data(), S_IRWXU | S_IRWXG | S_IROTH) == -1) { std::cerr << errno << ": Error in recursive dir creation. " << path << std::endl; error_thrown = true; } if (error_thrown) return -1; } return 0; } /** * Reads the entire file from given file discriptor. * @param fd File descriptor to be read. * @param buf String buffer to be populated. * @param offset Begin offset of the file to read. * @return Returns number of bytes read in a successful read and -1 on error. */ int read_from_fd(const int fd, std::string &buf, const off_t offset) { struct stat st; if (fstat(fd, &st) == -1) { std::cerr << errno << ": Error in stat for reading entire file." << std::endl; return -1; } buf.resize(st.st_size - offset); return pread(fd, buf.data(), buf.size(), offset); } /** * Provide a safe std::string overload for realpath. * @param path Path. * @returns Returns the realpath as string. */ const std::string realpath(std::string_view path) { std::array buffer; ::realpath(path.data(), buffer.data()); buffer[PATH_MAX] = '\0'; return buffer.data(); } /** * Clears signal mask and signal handlers from the caller. * Called by other processes forked from sagent threads so they get detatched from * the sagent signal setup. */ void fork_detach() { // Restore signal handlers to defaults. signal(SIGINT, SIG_DFL); signal(SIGSEGV, SIG_DFL); signal(SIGABRT, SIG_DFL); // Remove any signal masks applied by sagent. sigset_t mask; sigemptyset(&mask); pthread_sigmask(SIG_SETMASK, &mask, NULL); // Set process group id (so the terminal doesn't send kill signals to forked children). setpgrp(); } // Applies signal mask to the calling thread. void mask_signal() { sigset_t mask; sigemptyset(&mask); sigaddset(&mask, SIGINT); sigaddset(&mask, SIGPIPE); pthread_sigmask(SIG_BLOCK, &mask, NULL); } /** * Sleeps the current thread for specified no. of milliseconds. */ void sleep(const uint64_t milliseconds) { std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds)); } /** * Returns current time in UNIX epoch milliseconds. */ uint64_t get_epoch_milliseconds() { return std::chrono::duration_cast>( std::chrono::system_clock::now().time_since_epoch()) .count(); } /** * Remove a directory recursively with it's content. FTW_DEPTH is provided so all of the files and subdirectories within * The path will be processed. FTW_PHYS is provided so symbolic links won't be followed. */ int remove_directory_recursively(std::string_view dir_path) { return nftw( dir_path.data(), [](const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf) { return remove(fpath); }, 1, FTW_DEPTH | FTW_PHYS); } // Kill a process with a signal and if specified, wait until it stops running. int kill_process(const pid_t pid, const bool wait, const int signal) { if (kill(pid, signal) == -1) { LOG_ERROR << errno << ": Error issuing signal to pid " << pid; return -1; } const int wait_options = wait ? 0 : WNOHANG; if (waitpid(pid, NULL, wait_options) == -1) { LOG_ERROR << errno << ": waitpid after kill (pid:" << pid << ") failed."; return -1; } return 0; } } // namespace util