Mercurial > irccd
view libirccd-core/irccd/system.cpp @ 762:28f493661157
Misc: prefix all macros with IRCCD_
author | David Demelier <markand@malikania.fr> |
---|---|
date | Sun, 12 Aug 2018 09:40:36 +0200 |
parents | 2496ebc42b07 |
children | 8c44bbcbbab9 |
line wrap: on
line source
/* * system.cpp -- platform dependent functions for system inspection * * Copyright (c) 2013-2018 David Demelier <markand@malikania.fr> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <cassert> #include <cerrno> #include <cstdlib> #include <cstring> #include <ctime> #include <stdexcept> #include <string> #include <boost/dll.hpp> #include <boost/filesystem.hpp> #include <boost/predef/os.h> #include "sysconfig.hpp" #if BOOST_OS_WINDOWS # include <sys/timeb.h> # include <shlobj.h> #else # include <sys/utsname.h> # include <sys/types.h> # include <sys/param.h> # include <sys/time.h> # include <unistd.h> #endif #if BOOST_OS_LINUX # include <sys/sysinfo.h> #endif #if BOOST_OS_MACOS # include <sys/sysctl.h> # include <libproc.h> #endif #if defined(IRCCD_HAVE_GETLOGIN) # include <unistd.h> #endif #include "system.hpp" #include "string_util.hpp" #include "xdg.hpp" namespace irccd::sys { namespace { // {{{ base_directory /* * base_directory * ------------------------------------------------------------------ * * Get the base program directory. * * If irccd has been compiled with relative paths, the base directory is * evaluated by climbing the `bindir' directory from the executable path. * * Otherwise, use the installation prefix. */ auto base_directory() -> boost::filesystem::path { static const boost::filesystem::path bindir(IRCCD_INSTALL_BINDIR); static const boost::filesystem::path prefix(IRCCD_INSTALL_PREFIX); boost::filesystem::path path("."); if (bindir.is_relative()) { try { path = boost::dll::program_location(); path = path.parent_path(); } catch (...) { path = "."; } // Compute relative base directory. for (auto len = std::distance(bindir.begin(), bindir.end()); len > 0; len--) path = path.parent_path(); if (path.empty()) path = "."; } else path = prefix; return path; } // }}} // {{{ system_directory /* * system_directory * ------------------------------------------------------------------ * * Compute the system directory path for the given component. * * Referenced by: * - cachedir, * - datadir, * - sysconfigdir, * - plugindir. */ auto system_directory(const std::string& component) -> boost::filesystem::path { boost::filesystem::path path(component); if (path.is_relative()) path = base_directory() / component; return path.string(); } // }}} // {{{ user_config_directory /* * user_config_directory * ------------------------------------------------------------------ * * Get user configuration directory. * * Referenced by: config_filenames. * Requires: * - Windows: * - <shlobj.h> */ auto user_config_directory() -> boost::filesystem::path { boost::filesystem::path path; #if BOOST_OS_WINDOWS char folder[MAX_PATH] = {0}; if (SHGetFolderPathA(nullptr, CSIDL_LOCAL_APPDATA, nullptr, 0, folder) == S_OK) { path /= folder; path /= "\\irccd\\config"; } else path = "."; #else try { path = xdg().config_home(); } catch (...) { path = sys::env("HOME"); path /= ".config"; } path /= "irccd"; #endif return path; } // }}} // {{{ user_plugin_directory /* * user_plugin_directory * ------------------------------------------------------------------ * * Referenced by: plugin_filenames. * Requires: * - Windows: * - <shlobj.h> * * Like add user_config_directory but for plugins. */ auto user_plugin_directory() -> boost::filesystem::path { boost::filesystem::path path; #if BOOST_OS_WINDOWS char folder[MAX_PATH] = {0}; if (SHGetFolderPathA(nullptr, CSIDL_LOCAL_APPDATA, nullptr, 0, folder) == S_OK) { path /= folder; path /= "\\irccd\\share"; } #else try { path = xdg().data_home(); } catch (...) { path = sys::env("HOME"); path /= ".local/share"; } path /= "irccd"; #endif return path / "plugins"; } // }}} } // !namespace // {{{ set_program_name void set_program_name(std::string name) noexcept { #if defined(IRCCD_HAVE_SETPROGNAME) static std::string save = name; setprogname(save.c_str()); #else (void)name; #endif } // }}} // {{{ name auto name() -> std::string { #if BOOST_OS_LINUX return "Linux"; #elif BOOST_OS_WINDOWS return "Windows"; #elif BOOST_OS_BSD_FREE return "FreeBSD"; #elif BOOST_OS_BSD_DRAGONFLY return "DragonFlyBSD"; #elif BOOST_OS_BSD_OPEN return "OpenBSD"; #elif BOOST_OS_BSD_NET return "NetBSD"; #elif BOOST_OS_MACOS return "macOS"; #elif BOOST_OS_ANDROID return "Android"; #elif BOOST_OS_AIX return "Aix"; #elif BOOST_OS_HAIKU return "Haiku"; #elif BOOST_OS_IOS return "iOS"; #elif BOOST_OS_SOLARIS return "Solaris"; #else return "Unknown"; #endif } // }}} // {{{ version /* * Requires: * - Windows: * - <windows.h> * - Others: * - <sys/utsname.h> */ auto version() -> std::string { #if BOOST_OS_WINDOWS const auto version = GetVersion(); const auto major = (DWORD)(LOBYTE(LOWORD(version))); const auto minor = (DWORD)(HIBYTE(LOWORD(version))); return std::to_string(major) + "." + std::to_string(minor); #else struct utsname uts; if (::uname(&uts) < 0) throw std::runtime_error(std::strerror(errno)); return std::string(uts.release); #endif } // }}} // {{{ uptime /* * Requires: * - Windows: * - <windows.h> * - Linux: * - <sys/sysinfo.h> * - Mac: * - <sys/types.h> * - <sys/sysctl.h> * - Others: * - <ctime> */ auto uptime() -> std::uint64_t { #if BOOST_OS_WINDOWS return ::GetTickCount64() / 1000; #elif BOOST_OS_LINUX struct sysinfo info; if (sysinfo(&info) < 0) throw std::runtime_error(std::strerror(errno)); return info.uptime; #elif BOOST_OS_MACOS struct timeval boottime; size_t length = sizeof (boottime); int mib[2] = { CTL_KERN, KERN_BOOTTIME }; if (sysctl(mib, 2, &boottime, &length, nullptr, 0) < 0) throw std::runtime_error(std::strerror(errno)); time_t bsec = boottime.tv_sec, csec = time(nullptr); return difftime(csec, bsec); #else struct timespec ts; if (clock_gettime(CLOCK_UPTIME, &ts) < 0) throw std::runtime_error(std::strerror(errno)); return ts.tv_sec; #endif } // }}} // {{{ ticks /* * Requires: * - Windows: * - <sys/timeb.h> * - Others: * - <sys/times.h> */ auto ticks() -> std::uint64_t { #if BOOST_OS_WINDOWS _timeb tp; _ftime(&tp); return tp.time * 1000LL + tp.millitm; #else struct timeval tp; gettimeofday(&tp, NULL); return tp.tv_sec * 1000LL + tp.tv_usec / 1000; #endif } // }}} // {{{ home /* * Requires: * - Windows: * - <shlobj.h> */ auto home() -> std::string { #if BOOST_OS_WINDOWS char path[MAX_PATH]; if (SHGetFolderPathA(nullptr, CSIDL_LOCAL_APPDATA, nullptr, 0, path) != S_OK) return ""; return std::string(path); #else return env("HOME"); #endif } // }}} // {{{ env /* * Requires: * - <cstdlib> */ auto env(const std::string& var) -> std::string { const auto value = std::getenv(var.c_str()); if (value == nullptr) return ""; return value; } // }}} // {{{ cachedir auto cachedir() -> boost::filesystem::path { return system_directory(IRCCD_INSTALL_LOCALSTATEDIR) / "cache/irccd"; } // }}} // {{{ datadir auto datadir() -> boost::filesystem::path { return system_directory(IRCCD_INSTALL_DATADIR); } // }}} // {{{ sysconfdir auto sysconfdir() -> boost::filesystem::path { return system_directory(IRCCD_INSTALL_SYSCONFDIR) / "irccd"; } // }}} // {{{ plugindir auto plugindir() -> boost::filesystem::path { return system_directory(IRCCD_INSTALL_LIBDIR) / "irccd"; } // }}} // {{{ username /* * Requires: * - <unistd.h> */ auto username() -> std::string { #if defined(IRCCD_HAVE_GETLOGIN) auto v = getlogin(); if (v) return v; #endif return ""; } // }}} // {{{ config_filenames auto config_filenames(std::string_view file) -> std::vector<std::string> { // TODO: remove this once we can use std::filesystem. const std::string filename(file); return { (user_config_directory() / filename).string(), (sysconfdir() / filename).string() }; } // }}} // {{{ plugin_filenames auto plugin_filenames(const std::string& name, const std::vector<std::string>& extensions) -> std::vector<std::string> { assert(!extensions.empty()); std::vector<std::string> result; for (const auto& ext : extensions) result.push_back((user_plugin_directory() / (name + ext)).string()); for (const auto& ext : extensions) result.push_back((plugindir() / (name + ext)).string()); return result; } // }}} } // !irccd::sys