Merge branch 'main' into battery-power-2

This commit is contained in:
vsey 2024-01-03 20:52:30 +01:00 committed by GitHub
commit b28c5ffc40
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 1899 additions and 163 deletions

View file

@ -11,6 +11,7 @@ on:
- 'src/**'
- '!src/linux/**'
- '!src/osx/**'
- '!src/openbsd/**'
- 'include/**'
- 'Makefile'
- '.github/workflows/continuous-build-freebsd.yml'
@ -21,6 +22,7 @@ on:
- 'src/**'
- '!src/linux/**'
- '!src/osx/**'
- '!src/openbsd/**'
- 'include/**'
- 'Makefile'
- '.github/workflows/continuous-build-freebsd.yml'

View file

@ -11,6 +11,7 @@ on:
- 'src/**'
- '!src/osx/**'
- '!src/freebsd/**'
- '!src/openbsd/**'
- 'include/**'
- 'Makefile'
- '.github/workflows/continuous-build-linux.yml'
@ -21,6 +22,7 @@ on:
- 'src/**'
- '!src/osx/**'
- '!src/freebsd/**'
- '!src/openbsd/**'
- 'include/**'
- 'Makefile'
- '.github/workflows/continuous-build-linux.yml'

View file

@ -11,6 +11,7 @@ on:
- 'src/**'
- '!src/linux/**'
- '!src/freebsd/**'
- '!src/openbsd/**'
- 'include/**'
- 'Makefile'
- '.github/workflows/continuous-build-macos.yml'
@ -21,6 +22,7 @@ on:
- 'src/**'
- '!src/linux/**'
- '!src/freebsd/**'
- '!src/openbsd/**'
- 'include/**'
- 'Makefile'
- '.github/workflows/continuous-build-macos.yml'
@ -44,18 +46,18 @@ jobs:
with:
name: btop-x86_64-macos11-BigSur
path: 'bin/*'
build-macos12:
runs-on: macos-12
steps:
- uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: latest-stable
xcode-version: latest-stable
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Compile
run: |
make CXX=g++-12 ARCH=x86_64 STATIC=true STRIP=true

View file

@ -0,0 +1,58 @@
name: Continuous Build OpenBSD
on:
workflow_dispatch:
push:
branches:
- main
tags-ignore:
- '*.*'
paths:
- 'src/**'
- '!src/linux/**'
- '!src/osx/**'
- '!src/freebsd/**'
- 'include/**'
- 'Makefile'
- '.github/workflows/continuous-build-openbsd.yml'
pull_request:
branches:
- main
paths:
- 'src/**'
- '!src/linux/**'
- '!src/osx/**'
- '!src/freebsd/**'
- 'include/**'
- 'Makefile'
- '.github/workflows/continuous-build-openbsd.yml'
jobs:
build-openbsd:
runs-on: ubuntu-22.04
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Compile
uses: vmactions/openbsd-vm@v1
with:
release: '7.4'
usesh: true
prepare: |
pkg_add gmake gcc%11 g++%11 coreutils git
git config --global --add safe.directory /home/runner/work/btop/btop
run: |
gmake CXX=eg++ STATIC=true STRIP=true
GIT_HASH=$(git rev-parse --short "$GITHUB_SHA")
mv bin/btop bin/btop-GCC11-"$GIT_HASH"
ls -alh bin
- uses: actions/upload-artifact@v3
with:
name: btop-x86_64-openbsd-7.4
path: 'bin/*'
if-no-files-found: error

View file

@ -73,32 +73,9 @@ ifeq ($(CXX_IS_CLANG),true)
ifneq ($(shell test $(CXX_VERSION_MAJOR) -lt $(MIN_CLANG_VERSION); echo $$?),0)
CLANG_WORKS := true
endif
endif
ifeq ($(CLANG_WORKS),false)
#? Try to find a newer GCC version
ifeq ($(shell command -v g++-13 >/dev/null; echo $$?),0)
CXX := g++-13
else ifeq ($(shell command -v g++13 >/dev/null; echo $$?),0)
CXX := g++13
else ifeq ($(shell command -v g++-12 >/dev/null; echo $$?),0)
CXX := g++-12
else ifeq ($(shell command -v g++12 >/dev/null; echo $$?),0)
CXX := g++12
else ifeq ($(shell command -v g++-11 >/dev/null; echo $$?),0)
CXX := g++-11
else ifeq ($(shell command -v g++11 >/dev/null; echo $$?),0)
CXX := g++11
else ifeq ($(shell command -v g++ >/dev/null; echo $$?),0)
CXX := g++
else
GCC_NOT_FOUND := true
endif
ifndef GCC_NOT_FOUND
override CXX_VERSION := $(shell $(CXX) -dumpfullversion -dumpversion || echo 0)
override CXX_VERSION_MAJOR := $(shell echo $(CXX_VERSION) | cut -d '.' -f 1)
ifneq ($(shell test $(CXX_VERSION_MAJOR) -lt 10; echo $$?),0)
GCC_WORKS := true
endif
else
ifneq ($(shell test $(CXX_VERSION_MAJOR) -lt 10; echo $$?),0)
GCC_WORKS := true
endif
endif
@ -158,6 +135,12 @@ else ifeq ($(PLATFORM_LC),macos)
THREADS := $(shell sysctl -n hw.ncpu || echo 1)
override ADDFLAGS += -framework IOKit -framework CoreFoundation -Wno-format-truncation
SU_GROUP := wheel
else ifeq ($(PLATFORM_LC),openbsd)
PLATFORM_DIR := openbsd
THREADS := $(shell sysctl -n hw.ncpu || echo 1)
override ADDFLAGS += -lkvm
export MAKE = gmake
SU_GROUP := wheel
else
$(error $(shell printf "\033[1;91mERROR: \033[97mUnsupported platform ($(PLATFORM))\033[0m"))
endif

View file

@ -7,6 +7,7 @@
![Linux](https://img.shields.io/badge/-Linux-grey?logo=linux)
![macOS](https://img.shields.io/badge/-OSX-black?logo=apple)
![FreeBSD](https://img.shields.io/badge/-FreeBSD-red?logo=freebsd)
![OpenBSD](https://img.shields.io/badge/-OpenBSD-black?logo=openbsd)
![Usage](https://img.shields.io/badge/Usage-System%20resource%20monitor-yellow)
![c++20](https://img.shields.io/badge/cpp-c%2B%2B20-green)
![latest_release](https://img.shields.io/github/v/tag/aristocratos/btop?label=release)
@ -17,6 +18,7 @@
[![Continuous Build Linux](https://github.com/aristocratos/btop/actions/workflows/continuous-build-linux.yml/badge.svg)](https://github.com/aristocratos/btop/actions/workflows/continuous-build-linux.yml)
[![Continuous Build macOS](https://github.com/aristocratos/btop/actions/workflows/continuous-build-macos.yml/badge.svg)](https://github.com/aristocratos/btop/actions/workflows/continuous-build-macos.yml)
[![Continuous Build FreeBSD](https://github.com/aristocratos/btop/actions/workflows/continuous-build-freebsd.yml/badge.svg)](https://github.com/aristocratos/btop/actions/workflows/continuous-build-freebsd.yml)
[![Continuous Build OpenBSD](https://github.com/aristocratos/btop/actions/workflows/continuous-build-openbsd.yml/badge.svg)](https://github.com/aristocratos/btop/actions/workflows/continuous-build-openbsd.yml)
## Index
@ -33,6 +35,7 @@
* [Compilation Linux](#compilation-linux)
* [Compilation macOS](#compilation-macos-osx)
* [Compilation FreeBSD](#compilation-freebsd)
* [Compilation OpenBSD](#compilation-openbsd)
* [GPU compatibility](#gpu-compatibility)
* [Installing the snap](#installing-the-snap)
* [Configurability](#configurability)
@ -868,6 +871,100 @@ Also needs a UTF8 locale and a font that covers:
</details>
## Compilation OpenBSD
Requires at least GCC 10.
Note that GNU make (`gmake`) is required to compile on OpenBSD.
<details>
<summary>
### With gmake
</summary>
1. **Install dependencies**
```bash
pkg_add gmake gcc%11 g++%11 coreutils git
```
2. **Clone repository**
```bash
git clone https://github.com/aristocratos/btop.git
cd btop
```
3. **Compile**
```bash
gmake CXX=eg++
```
Options for make:
| Flag | Description |
|---------------------------------|-------------------------------------------------------------------------|
| `VERBOSE=true` | To display full compiler/linker commands |
| `STATIC=true` | For static compilation (only libgcc and libstdc++) |
| `QUIET=true` | For less verbose output |
| `STRIP=true` | To force stripping of debug symbols (adds `-s` linker flag) |
| `DEBUG=true` | Sets OPTFLAGS to `-O0 -g` and enables more verbose debug logging |
| `ARCH=<architecture>` | To manually set the target architecture |
| `ADDFLAGS=<flags>` | For appending flags to both compiler and linker |
| `CXX=<compiler>` | Manualy set which compiler to use |
Example: `gmake ADDFLAGS=-march=native` might give a performance boost if compiling only for your own system.
4. **Install**
```bash
sudo gmake install
```
Append `PREFIX=/target/dir` to set target, default: `/usr/local`
Notice! Only use "sudo" when installing to a NON user owned directory.
5. **(Recommended) Set suid bit to make btop always run as root (or other user)**
```bash
sudo gmake setuid
```
No need for `sudo` to see information for non user owned processes and to enable signal sending to any process.
Run after make install and use same PREFIX if any was used at install.
Set `SU_USER` and `SU_GROUP` to select user and group, default is `root` and `wheel`
* **Uninstall**
```bash
sudo gmake uninstall
```
* **Remove any object files from source dir**
```bash
gmake clean
```
* **Remove all object files, binaries and created directories in source dir**
```bash
gmake distclean
```
* **Show help**
```bash
gmake help
```
</details>
## Installing the snap
[![btop](https://snapcraft.io/btop/badge.svg)](https://snapcraft.io/btop)

View file

@ -45,6 +45,7 @@ parts:
source-type: git
plugin: make
make-parameters:
- CXX=g++-11
- PREFIX=/usr/local
- STATIC=true
- ADDFLAGS="-D SNAPPED"

View file

@ -16,6 +16,7 @@ indent = tab
tab-size = 4
*/
#include <algorithm>
#include <csignal>
#include <clocale>
#include <pthread.h>
@ -51,6 +52,7 @@ tab-size = 4
#include "btop_theme.hpp"
#include "btop_draw.hpp"
#include "btop_menu.hpp"
#include "fmt/core.h"
using std::atomic;
using std::cout;
@ -109,15 +111,16 @@ namespace Global {
bool arg_tty{}; // defaults to false
bool arg_low_color{}; // defaults to false
int arg_preset = -1;
int arg_update = 0;
}
//* A simple argument parser
void argumentParser(const int& argc, char **argv) {
void argumentParser(const int argc, char **argv) {
for(int i = 1; i < argc; i++) {
const string argument = argv[i];
if (is_in(argument, "-h", "--help")) {
fmt::println(
"usage: btop [-h] [-v] [-/+t] [-p <id>] [--utf-force] [--debug]\n\n"
"usage: btop [-h] [-v] [-/+t] [-p <id>] [-u <ms>] [--utf-force] [--debug]\n\n"
"optional arguments:\n"
" -h, --help show this help message and exit\n"
" -v, --version show version info and exit\n"
@ -125,6 +128,7 @@ void argumentParser(const int& argc, char **argv) {
" -t, --tty_on force (ON) tty mode, max 16 colors and tty friendly graph symbols\n"
" +t, --tty_off force (OFF) tty mode\n"
" -p, --preset <id> start with preset, integer value between 0-9\n"
" -u, --update <ms> set the program update rate in milliseconds\n"
" --utf-force force start even if no UTF-8 locale was detected\n"
" --debug start in DEBUG mode: shows microsecond timer for information collect\n"
" and screen draw functions and sets loglevel to DEBUG"
@ -159,6 +163,19 @@ void argumentParser(const int& argc, char **argv) {
exit(1);
}
}
else if (is_in(argument, "-u", "--update")) {
if (++i >= argc) {
fmt::println("ERROR: Update option needs an argument");
exit(1);
}
const std::string value = argv[i];
if (isint(value)) {
Global::arg_update = std::clamp(std::stoi(value), 100, Config::ONE_DAY_MILLIS);
} else {
fmt::println("ERROR: Invalid update rate");
exit(1);
}
}
else if (argument == "--utf-force")
Global::utf_force = true;
else if (argument == "--debug")
@ -176,7 +193,7 @@ void term_resize(bool force) {
static atomic<bool> resizing (false);
if (Input::polling) {
Global::resized = true;
Input::interrupt = true;
Input::interrupt();
return;
}
atomic_lock lck(resizing, true);
@ -246,7 +263,7 @@ void term_resize(bool force) {
else if (not Term::refresh()) break;
}
Input::interrupt = true;
Input::interrupt();
}
//* Exit handler; stops threads, restores terminal and saves config changes
@ -255,7 +272,7 @@ void clean_quit(int sig) {
Global::quitting = true;
Runner::stop();
if (Global::_runner_started) {
#ifdef __APPLE__
#if defined __APPLE__ || defined __OpenBSD__
if (pthread_join(Runner::runner_id, nullptr) != 0) {
Logger::warning("Failed to join _runner thread on exit!");
pthread_cancel(Runner::runner_id);
@ -291,7 +308,7 @@ void clean_quit(int sig) {
const auto excode = (sig != -1 ? sig : 0);
#ifdef __APPLE__
#if defined __APPLE__ || defined __OpenBSD__
_Exit(excode);
#else
quick_exit(excode);
@ -321,7 +338,7 @@ void _signal_handler(const int sig) {
if (Runner::active) {
Global::should_quit = true;
Runner::stopping = true;
Input::interrupt = true;
Input::interrupt();
}
else {
clean_quit(0);
@ -331,7 +348,7 @@ void _signal_handler(const int sig) {
if (Runner::active) {
Global::should_sleep = true;
Runner::stopping = true;
Input::interrupt = true;
Input::interrupt();
}
else {
_sleep();
@ -343,6 +360,9 @@ void _signal_handler(const int sig) {
case SIGWINCH:
term_resize();
break;
case SIGUSR1:
// Input::poll interrupt
break;
}
}
@ -477,7 +497,7 @@ namespace Runner {
if (pt_lck.status != 0) {
Global::exit_error_msg = "Exception in runner thread -> pthread_mutex_lock error id: " + to_string(pt_lck.status);
Global::thread_exception = true;
Input::interrupt = true;
Input::interrupt();
stopping = true;
}
@ -488,7 +508,7 @@ namespace Runner {
if (active) {
Global::exit_error_msg = "Runner thread failed to get active lock!";
Global::thread_exception = true;
Input::interrupt = true;
Input::interrupt();
stopping = true;
}
if (stopping or Global::resized) {
@ -558,7 +578,7 @@ namespace Runner {
coreNum_reset = false;
Cpu::core_mapping = Cpu::get_core_mapping();
Global::resized = true;
Input::interrupt = true;
Input::interrupt();
continue;
}
@ -655,7 +675,7 @@ namespace Runner {
catch (const std::exception& e) {
Global::exit_error_msg = "Exception in runner thread -> " + string{e.what()};
Global::thread_exception = true;
Input::interrupt = true;
Input::interrupt();
stopping = true;
}
@ -829,29 +849,23 @@ int main(int argc, char **argv) {
//? Call argument parser if launched with arguments
if (argc > 1) argumentParser(argc, argv);
//? Setup paths for config, log and user themes
for (const auto& env : {"XDG_CONFIG_HOME", "HOME"}) {
if (std::getenv(env) != nullptr and access(std::getenv(env), W_OK) != -1) {
Config::conf_dir = fs::path(std::getenv(env)) / (((string)env == "HOME") ? ".config/btop" : "btop");
break;
}
}
if (Config::conf_dir.empty()) {
fmt::println("WARNING: Could not get path user HOME folder.\n"
"Make sure $XDG_CONFIG_HOME or $HOME environment variables is correctly set to fix this.");
}
else {
if (std::error_code ec; not fs::is_directory(Config::conf_dir) and not fs::create_directories(Config::conf_dir, ec)) {
fmt::println("WARNING: Could not create or access btop config directory. Logging and config saving disabled.\n"
"Make sure $XDG_CONFIG_HOME or $HOME environment variables is correctly set to fix this.");
}
else {
{
const auto config_dir = Config::get_config_dir();
if (config_dir.has_value()) {
Config::conf_dir = config_dir.value();
Config::conf_file = Config::conf_dir / "btop.conf";
Logger::logfile = Config::conf_dir / "btop.log";
Theme::user_theme_dir = Config::conf_dir / "themes";
if (not fs::exists(Theme::user_theme_dir) and not fs::create_directory(Theme::user_theme_dir, ec)) Theme::user_theme_dir.clear();
// If necessary create the user theme directory
std::error_code error;
if (not fs::exists(Theme::user_theme_dir, error) and not fs::create_directories(Theme::user_theme_dir, error)) {
Theme::user_theme_dir.clear();
Logger::warning("Failed to create user theme directory: " + error.message());
}
}
}
//? Try to find global btop theme path relative to binary path
#ifdef __linux__
{ std::error_code ec;
@ -931,7 +945,7 @@ int main(int argc, char **argv) {
catch (...) { found.clear(); }
}
}
//
#ifdef __APPLE__
if (found.empty()) {
CFLocaleRef cflocale = CFLocaleCopyCurrent();
@ -975,7 +989,7 @@ int main(int argc, char **argv) {
Config::set("tty_mode", true);
Logger::info("Forcing tty mode: setting 16 color mode and using tty friendly graph symbols");
}
#ifndef __APPLE__
#if not defined __APPLE__ && not defined __OpenBSD__
else if (not Global::arg_tty and Term::current_tty.starts_with("/dev/tty")) {
Config::set("tty_mode", true);
Logger::info("Real tty detected: setting 16 color mode and using tty friendly graph symbols");
@ -1014,6 +1028,12 @@ int main(int argc, char **argv) {
std::signal(SIGTSTP, _signal_handler);
std::signal(SIGCONT, _signal_handler);
std::signal(SIGWINCH, _signal_handler);
std::signal(SIGUSR1, _signal_handler);
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, SIGUSR1);
pthread_sigmask(SIG_BLOCK, &mask, &Input::signal_mask);
//? Start runner thread
Runner::thread_sem_init();
@ -1035,9 +1055,10 @@ int main(int argc, char **argv) {
{
const auto [x, y] = Term::get_min_size(Config::getS("shown_boxes"));
if (Term::height < y or Term::width < x) {
pthread_sigmask(SIG_SETMASK, &Input::signal_mask, &mask);
term_resize(true);
pthread_sigmask(SIG_SETMASK, &mask, nullptr);
Global::resized = false;
Input::interrupt = false;
}
}
@ -1050,6 +1071,9 @@ int main(int argc, char **argv) {
//? ------------------------------------------------ MAIN LOOP ----------------------------------------------------
if (Global::arg_update != 0) {
Config::set("update_ms", Global::arg_update);
}
uint64_t update_ms = Config::getI("update_ms");
auto future_time = time_ms();

View file

@ -24,6 +24,7 @@ tab-size = 4
#include <utility>
#include <fmt/core.h>
#include <sys/statvfs.h>
#include "btop_config.hpp"
#include "btop_shared.hpp"
@ -323,6 +324,65 @@ namespace Config {
};
std::unordered_map<std::string_view, int> intsTmp;
// Returns a valid config dir or an empty optional
// The config dir might be read only, a warning is printed, but a path is returned anyway
[[nodiscard]] std::optional<fs::path> get_config_dir() noexcept {
fs::path config_dir;
{
std::error_code error;
if (const auto xdg_config_home = std::getenv("XDG_CONFIG_HOME"); xdg_config_home != nullptr) {
if (fs::exists(xdg_config_home, error)) {
config_dir = fs::path(xdg_config_home) / "btop";
}
} else if (const auto home = std::getenv("HOME"); home != nullptr) {
error.clear();
if (fs::exists(home, error)) {
config_dir = fs::path(home) / ".config" / "btop";
}
if (error) {
fmt::print(stderr, "\033[0;31mWarning: \033[0m{} could not be accessed: {}\n", config_dir.string(), error.message());
config_dir = "";
}
}
}
// FIXME: This warnings can be noisy if the user deliberately has a non-writable config dir
// offer an alternative | disable messages by default | disable messages if config dir is not writable | disable messages with a flag
// FIXME: Make happy path not branch
if (not config_dir.empty()) {
std::error_code error;
if (fs::exists(config_dir, error)) {
if (fs::is_directory(config_dir, error)) {
struct statvfs stats {};
if ((fs::status(config_dir, error).permissions() & fs::perms::owner_write) == fs::perms::owner_write and
statvfs(config_dir.c_str(), &stats) == 0 and (stats.f_flag & ST_RDONLY) == 0) {
return config_dir;
} else {
fmt::print(stderr, "\033[0;31mWarning: \033[0m`{}` is not writable\n", fs::absolute(config_dir).string());
// If the config is readable we can still use the provided config, but changes will not be persistent
if ((fs::status(config_dir, error).permissions() & fs::perms::owner_read) == fs::perms::owner_read) {
fmt::print(stderr, "\033[0;31mWarning: \033[0mLogging is disabled, config changes are not persistent\n");
return config_dir;
}
}
} else {
fmt::print(stderr, "\033[0;31mWarning: \033[0m`{}` is not a directory\n", fs::absolute(config_dir).string());
}
} else {
// Doesn't exist
if (fs::create_directories(config_dir, error)) {
return config_dir;
} else {
fmt::print(stderr, "\033[0;31mWarning: \033[0m`{}` could not be created: {}\n", fs::absolute(config_dir).string(), error.message());
}
}
} else {
fmt::print(stderr, "\033[0;31mWarning: \033[0mCould not determine config path: Make sure `$XDG_CONFIG_HOME` or `$HOME` is set\n");
}
fmt::print(stderr, "\033[0;31mWarning: \033[0mLogging is disabled, config changes are not persistent\n");
return {};
}
bool _locked(const std::string_view name) {
atomic_wait(writelock, true);
if (not write_new and rng::find_if(descriptions, [&name](const auto& a) { return a.at(0) == name; }) != descriptions.end())
@ -431,8 +491,8 @@ namespace Config {
if (name == "update_ms" and i_value < 100)
validError = "Config value update_ms set too low (<100).";
else if (name == "update_ms" and i_value > 86400000)
validError = "Config value update_ms set too high (>86400000).";
else if (name == "update_ms" and i_value > ONE_DAY_MILLIS)
validError = fmt::format("Config value update_ms set too high (>{}).", ONE_DAY_MILLIS);
else
return true;
@ -597,12 +657,17 @@ namespace Config {
}
void load(const fs::path& conf_file, vector<string>& load_warnings) {
std::error_code error;
if (conf_file.empty())
return;
else if (not fs::exists(conf_file)) {
else if (not fs::exists(conf_file, error)) {
write_new = true;
return;
}
if (error) {
return;
}
std::ifstream cread(conf_file);
if (cread.good()) {
vector<string> valid_names;

View file

@ -18,9 +18,10 @@ tab-size = 4
#pragma once
#include <filesystem>
#include <optional>
#include <string>
#include <vector>
#include <filesystem>
#include <unordered_map>
@ -57,6 +58,10 @@ namespace Config {
extern vector<string> available_batteries;
extern int current_preset;
constexpr int ONE_DAY_MILLIS = 1000 * 60 * 60 * 24;
[[nodiscard]] std::optional<std::filesystem::path> get_config_dir() noexcept;
//* Check if string only contains space separated valid names for boxes
bool check_boxes(const string& boxes);
@ -94,7 +99,7 @@ namespace Config {
}
//* Set config key <name> to int <value>
inline void set(const std::string_view name, const int& value) {
inline void set(const std::string_view name, const int value) {
if (_locked(name)) intsTmp.insert_or_assign(name, value);
else ints.at(name) = value;
}

View file

@ -16,12 +16,13 @@ indent = tab
tab-size = 4
*/
#include <iostream>
#include <limits>
#include <ranges>
#include <vector>
#include <thread>
#include <mutex>
#include <signal.h>
#include <sys/select.h>
#include <utility>
#include "btop_input.hpp"
@ -31,17 +32,6 @@ tab-size = 4
#include "btop_menu.hpp"
#include "btop_draw.hpp"
#include "btop_input.hpp"
#include "btop_tools.hpp"
#include "btop_config.hpp"
#include "btop_shared.hpp"
#include "btop_menu.hpp"
#include "btop_draw.hpp"
using std::cin;
using namespace Tools;
using namespace std::literals; // for operator""s
namespace rng = std::ranges;
@ -89,83 +79,45 @@ namespace Input {
{"[24~", "f12"}
};
std::atomic<bool> interrupt (false);
sigset_t signal_mask;
std::atomic<bool> polling (false);
array<int, 2> mouse_pos;
std::unordered_map<string, Mouse_loc> mouse_mappings;
deque<string> history(50, "");
string old_filter;
string input;
struct InputThr {
InputThr() : thr(run, this) {
}
static void run(InputThr* that) {
that->runImpl();
}
void runImpl() {
char ch = 0;
// TODO(pg83): read whole buffer
while (cin.get(ch)) {
std::lock_guard<std::mutex> g(lock);
current.push_back(ch);
if (current.size() > 100) {
current.clear();
}
}
}
size_t avail() {
std::lock_guard<std::mutex> g(lock);
return current.size();
}
std::string get() {
std::string res;
{
std::lock_guard<std::mutex> g(lock);
res.swap(current);
}
return res;
}
static InputThr& instance() {
// intentional memory leak, to simplify shutdown process
static InputThr* input = new InputThr();
return *input;
}
std::string current;
// TODO(pg83): use std::conditional_variable instead of sleep
std::mutex lock;
std::thread thr;
};
bool poll(int timeout) {
bool poll(const uint64_t timeout) {
atomic_lock lck(polling);
if (timeout < 1) return InputThr::instance().avail() > 0;
while (timeout > 0) {
if (interrupt) {
interrupt = false;
return false;
}
if (InputThr::instance().avail() > 0) return true;
sleep_ms(timeout < 10 ? timeout : 10);
timeout -= 10;
fd_set fds;
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds);
struct timespec wait;
struct timespec *waitptr = nullptr;
if(timeout != std::numeric_limits<uint64_t>::max()) {
wait.tv_sec = timeout / 1000;
wait.tv_nsec = (timeout % 1000) * 1000000;
waitptr = &wait;
}
if(pselect(STDIN_FILENO + 1, &fds, nullptr, nullptr, waitptr, &signal_mask) > 0) {
input.clear();
char buf[1024];
ssize_t count = 0;
while((count = read(STDIN_FILENO, buf, sizeof(buf))) > 0) {
input.append(std::string_view(buf, count));
}
return true;
}
return false;
}
string get() {
string key = InputThr::instance().get();
string key = input;
if (not key.empty()) {
//? Remove escape code prefix if present
if (key.substr(0, 2) == Fx::e) {
@ -238,12 +190,14 @@ namespace Input {
}
string wait() {
while (InputThr::instance().avail() < 1) {
sleep_ms(10);
}
while(not poll(std::numeric_limits<uint64_t>::max())) {}
return get();
}
void interrupt() {
kill(getpid(), SIGUSR1);
}
void clear() {
// do not need it, actually
}

View file

@ -29,9 +29,9 @@ using std::atomic;
using std::deque;
using std::string;
/* The input functions relies on the following std::cin options being set:
cin.sync_with_stdio(false);
cin.tie(nullptr);
/* The input functions rely on the following termios parameters being set:
Non-canonical mode (c_lflags & ~(ICANON))
VMIN and VTIME (c_cc) set to 0
These will automatically be set when running Term::init() from btop_tools.cpp
*/
@ -45,7 +45,9 @@ namespace Input {
//? line, col, height, width
extern std::unordered_map<string, Mouse_loc> mouse_mappings;
extern atomic<bool> interrupt;
//* Signal mask used during polling read
extern sigset_t signal_mask;
extern atomic<bool> polling;
//* Mouse column and line position
@ -55,7 +57,7 @@ namespace Input {
extern deque<string> history;
//* Poll keyboard & mouse input for <timeout> ms and return input availabilty as a bool
bool poll(int timeout=0);
bool poll(const uint64_t timeout=0);
//* Get a key or mouse action from input
string get();
@ -63,6 +65,9 @@ namespace Input {
//* Wait until input is available and return key
string wait();
//* Interrupt poll/wait
void interrupt();
//* Clears last entered key
void clear();

View file

@ -26,9 +26,10 @@ tab-size = 4
#include <utility>
#include <ranges>
#include <unistd.h>
#include <termios.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <unistd.h>
#include "unordered_map"
#include "widechar_width.hpp"
@ -36,7 +37,6 @@ tab-size = 4
#include "btop_tools.hpp"
#include "btop_config.hpp"
using std::cin;
using std::cout;
using std::floor;
using std::flush;
@ -76,7 +76,11 @@ namespace Term {
struct termios settings;
if (tcgetattr(STDIN_FILENO, &settings)) return false;
if (on) settings.c_lflag |= ICANON;
else settings.c_lflag &= ~(ICANON);
else {
settings.c_lflag &= ~(ICANON);
settings.c_cc[VMIN] = 0;
settings.c_cc[VTIME] = 0;
}
if (tcsetattr(STDIN_FILENO, TCSANOW, &settings)) return false;
if (on) setlinebuf(stdin);
else setbuf(stdin, nullptr);
@ -85,12 +89,27 @@ namespace Term {
}
bool refresh(bool only_check) {
struct winsize w;
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) < 0) return false;
if (width != w.ws_col or height != w.ws_row) {
// Query dimensions of '/dev/tty' of the 'STDOUT_FILENO' isn't avaiable.
// This variable is set in those cases to avoid calls to ioctl
constinit static bool uses_dev_tty = false;
struct winsize wsize {};
if (uses_dev_tty || ioctl(STDOUT_FILENO, TIOCGWINSZ, &wsize) < 0 || (wsize.ws_col == 0 && wsize.ws_row == 0)) {
Logger::error(R"(Couldn't determine terminal size of "STDOUT_FILENO"!)");
auto dev_tty = open("/dev/tty", O_RDONLY);
if (dev_tty != -1) {
ioctl(dev_tty, TIOCGWINSZ, &wsize);
close(dev_tty);
}
else {
Logger::error(R"(Couldn't determine terminal size of "/dev/tty"!)");
return false;
}
uses_dev_tty = true;
}
if (width != wsize.ws_col or height != wsize.ws_row) {
if (not only_check) {
width = w.ws_col;
height = w.ws_row;
width = wsize.ws_col;
height = wsize.ws_row;
}
return true;
}
@ -134,12 +153,12 @@ namespace Term {
tcgetattr(STDIN_FILENO, &initial_settings);
current_tty = (ttyname(STDIN_FILENO) != nullptr ? static_cast<string>(ttyname(STDIN_FILENO)) : "unknown");
//? Disable stream sync
cin.sync_with_stdio(false);
//? Disable stream sync - this does not seem to work on OpenBSD
#ifndef __OpenBSD__
cout.sync_with_stdio(false);
#endif
//? Disable stream ties
cin.tie(nullptr);
cout.tie(nullptr);
echo(false);
linebuffered(false);
@ -651,6 +670,7 @@ namespace Logger {
lose_priv neutered{};
std::error_code ec;
try {
// NOTE: `exist()` could throw but since we return with an empty logfile we don't care
if (fs::exists(logfile) and fs::file_size(logfile, ec) > 1024 << 10 and not ec) {
auto old_log = logfile;
old_log += ".1";

1295
src/openbsd/btop_collect.cpp Normal file

File diff suppressed because it is too large Load diff

157
src/openbsd/internal.h Normal file
View file

@ -0,0 +1,157 @@
/*
* Copyright (c) 2019-2021 Brian Callahan <bcallah@openbsd.org>
*
* Permission to use, copy, modify, and 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.
*/
struct sysctls {
const char *name;
int mib0;
int mib1;
int mib2;
} sysctlnames[] = {
{ "hw.machine", CTL_HW, HW_MACHINE, 0 },
{ "hw.model", CTL_HW, HW_MODEL, 0 },
{ "hw.ncpu", CTL_HW, HW_NCPU, 0 },
{ "hw.byteorder", CTL_HW, HW_BYTEORDER, 0 },
{ "hw.pagesize", CTL_HW, HW_PAGESIZE, 0 },
{ "hw.disknames", CTL_HW, HW_DISKNAMES, 0 },
{ "hw.diskcount", CTL_HW, HW_DISKCOUNT, 0 },
{ "hw.sensors", CTL_HW, HW_SENSORS, 0 },
{ "hw.model", CTL_HW, HW_MODEL, 0 },
{ "hw.ncpu", CTL_HW, HW_NCPU, 0 },
{ "hw.byteorder", CTL_HW, HW_BYTEORDER, 0 },
{ "hw.pagesize", CTL_HW, HW_PAGESIZE, 0 },
{ "hw.disknames", CTL_HW, HW_DISKNAMES, 0 },
{ "hw.diskcount", CTL_HW, HW_DISKCOUNT, 0 },
{ "hw.sensors", CTL_HW, HW_SENSORS, 0 },
{ "hw.cpuspeed", CTL_HW, HW_CPUSPEED, 0 },
{ "hw.setperf", CTL_HW, HW_SETPERF, 0 },
{ "hw.vendor", CTL_HW, HW_VENDOR, 0 },
{ "hw.product", CTL_HW, HW_PRODUCT, 0 },
{ "hw.serialno", CTL_HW, HW_SERIALNO, 0 },
{ "hw.uuid", CTL_HW, HW_UUID, 0 },
{ "hw.physmem", CTL_HW, HW_PHYSMEM64, 0 },
{ "hw.usermem", CTL_HW, HW_USERMEM64, 0 },
{ "hw.ncpufound", CTL_HW, HW_NCPUFOUND, 0 },
{ "hw.allowpowerdown", CTL_HW, HW_ALLOWPOWERDOWN, 0 },
{ "hw.perfpolicy", CTL_HW, HW_PERFPOLICY, 0 },
{ "hw.smt", CTL_HW, HW_SMT, 0 },
{ "hw.ncpuonline", CTL_HW, HW_NCPUONLINE, 0 },
{ "hw.cpuspeed", CTL_HW, HW_CPUSPEED, 0 },
{ "hw.setperf", CTL_HW, HW_SETPERF, 0 },
{ "hw.vendor", CTL_HW, HW_VENDOR, 0 },
{ "hw.product", CTL_HW, HW_PRODUCT, 0 },
{ "hw.serialno", CTL_HW, HW_SERIALNO, 0 },
{ "hw.uuid", CTL_HW, HW_UUID, 0 },
{ "hw.physmem", CTL_HW, HW_PHYSMEM64, 0 },
{ "hw.usermem", CTL_HW, HW_USERMEM64, 0 },
{ "hw.ncpufound", CTL_HW, HW_NCPUFOUND, 0 },
{ "hw.allowpowerdown", CTL_HW, HW_ALLOWPOWERDOWN, 0 },
{ "hw.perfpolicy", CTL_HW, HW_PERFPOLICY, 0 },
{ "hw.smt", CTL_HW, HW_SMT, 0 },
{ "hw.ncpuonline", CTL_HW, HW_NCPUONLINE, 0 },
{ "kern.ostype", CTL_KERN, KERN_OSTYPE, 0 },
{ "kern.osrelease", CTL_KERN, KERN_OSRELEASE, 0 },
{ "kern.osrevision", CTL_KERN, KERN_OSREV, 0 },
{ "kern.version", CTL_KERN, KERN_VERSION, 0 },
{ "kern.maxvnodes", CTL_KERN, KERN_MAXVNODES, 0 },
{ "kern.maxproc", CTL_KERN, KERN_MAXPROC, 0 },
{ "kern.maxfiles", CTL_KERN, KERN_MAXFILES, 0 },
{ "kern.argmax", CTL_KERN, KERN_ARGMAX, 0 },
{ "kern.securelevel", CTL_KERN, KERN_SECURELVL, 0 },
{ "kern.hostname", CTL_KERN, KERN_HOSTNAME, 0 },
{ "kern.hostid", CTL_KERN, KERN_HOSTID, 0 },
{ "kern.clockrate", CTL_KERN, KERN_CLOCKRATE, 0 },
{ "kern.profiling", CTL_KERN, KERN_PROF, 0 },
{ "kern.posix1version", CTL_KERN, KERN_POSIX1, 0 },
{ "kern.ngroups", CTL_KERN, KERN_NGROUPS, 0 },
{ "kern.job_control", CTL_KERN, KERN_JOB_CONTROL, 0 },
{ "kern.saved_ids", CTL_KERN, KERN_SAVED_IDS, 0 },
{ "kern.boottime", CTL_KERN, KERN_BOOTTIME, 0 },
{ "kern.domainname", CTL_KERN, KERN_DOMAINNAME, 0 },
{ "kern.maxpartitions", CTL_KERN, KERN_MAXPARTITIONS, 0 },
{ "kern.rawpartition", CTL_KERN, KERN_RAWPARTITION, 0 },
{ "kern.maxthread", CTL_KERN, KERN_MAXTHREAD, 0 },
{ "kern.nthreads", CTL_KERN, KERN_NTHREADS, 0 },
{ "kern.osversion", CTL_KERN, KERN_OSVERSION, 0 },
{ "kern.somaxconn", CTL_KERN, KERN_SOMAXCONN, 0 },
{ "kern.sominconn", CTL_KERN, KERN_SOMINCONN, 0 },
{ "kern.nosuidcoredump", CTL_KERN, KERN_NOSUIDCOREDUMP, 0 },
{ "kern.fsync", CTL_KERN, KERN_FSYNC, 0 },
{ "kern.sysvmsg", CTL_KERN, KERN_SYSVMSG, 0 },
{ "kern.sysvsem", CTL_KERN, KERN_SYSVSEM, 0 },
{ "kern.sysvshm", CTL_KERN, KERN_SYSVSHM, 0 },
{ "kern.msgbufsize", CTL_KERN, KERN_MSGBUFSIZE, 0 },
{ "kern.malloc", CTL_KERN, KERN_MALLOCSTATS, 0 },
{ "kern.cp_time", CTL_KERN, KERN_CPTIME, 0 },
{ "kern.nchstats", CTL_KERN, KERN_NCHSTATS, 0 },
{ "kern.forkstat", CTL_KERN, KERN_FORKSTAT, 0 },
{ "kern.tty", CTL_KERN, KERN_TTY, 0 },
{ "kern.ccpu", CTL_KERN, KERN_CCPU, 0 },
{ "kern.fscale", CTL_KERN, KERN_FSCALE, 0 },
{ "kern.nprocs", CTL_KERN, KERN_NPROCS, 0 },
{ "kern.msgbuf", CTL_KERN, KERN_MSGBUF, 0 },
{ "kern.pool", CTL_KERN, KERN_POOL, 0 },
{ "kern.stackgap_random", CTL_KERN, KERN_STACKGAPRANDOM, 0 },
{ "kern.sysvipc_info", CTL_KERN, KERN_SYSVIPC_INFO, 0 },
{ "kern.allowkmem", CTL_KERN, KERN_ALLOWKMEM, 0 },
{ "kern.witnesswatch", CTL_KERN, KERN_WITNESSWATCH, 0 },
{ "kern.splassert", CTL_KERN, KERN_SPLASSERT, 0 },
{ "kern.procargs", CTL_KERN, KERN_PROC_ARGS, 0 },
{ "kern.nfiles", CTL_KERN, KERN_NFILES, 0 },
{ "kern.ttycount", CTL_KERN, KERN_TTYCOUNT, 0 },
{ "kern.numvnodes", CTL_KERN, KERN_NUMVNODES, 0 },
{ "kern.mbstat", CTL_KERN, KERN_MBSTAT, 0 },
{ "kern.witness", CTL_KERN, KERN_WITNESS, 0 },
{ "kern.seminfo", CTL_KERN, KERN_SEMINFO, 0 },
{ "kern.shminfo", CTL_KERN, KERN_SHMINFO, 0 },
{ "kern.intrcnt", CTL_KERN, KERN_INTRCNT, 0 },
{ "kern.watchdog", CTL_KERN, KERN_WATCHDOG, 0 },
{ "kern.proc", CTL_KERN, KERN_PROC, 0 },
{ "kern.maxclusters", CTL_KERN, KERN_MAXCLUSTERS, 0 },
{ "kern.evcount", CTL_KERN, KERN_EVCOUNT, 0 },
{ "kern.timecounter", CTL_KERN, KERN_TIMECOUNTER, 0 },
{ "kern.maxlocksperuid", CTL_KERN, KERN_MAXLOCKSPERUID, 0 },
{ "kern.cp_time2", CTL_KERN, KERN_CPTIME2, 0 },
{ "kern.bufcachepercent", CTL_KERN, KERN_CACHEPCT, 0 },
{ "kern.file", CTL_KERN, KERN_FILE, 0 },
{ "kern.wxabort", CTL_KERN, KERN_WXABORT, 0 },
{ "kern.consdev", CTL_KERN, KERN_CONSDEV, 0 },
{ "kern.netlivelocks", CTL_KERN, KERN_NETLIVELOCKS, 0 },
{ "kern.pool_debug", CTL_KERN, KERN_POOL_DEBUG, 0 },
{ "kern.proc_cwd", CTL_KERN, KERN_PROC_CWD, 0 },
{ "kern.proc_nobroadcastkill", CTL_KERN, KERN_PROC_NOBROADCASTKILL, 0 },
{ "kern.proc_vmap", CTL_KERN, KERN_PROC_VMMAP, 0 },
{ "kern.global_ptrace", CTL_KERN, KERN_GLOBAL_PTRACE, 0 },
{ "kern.consbufsize", CTL_KERN, KERN_CONSBUFSIZE, 0 },
{ "kern.consbuf", CTL_KERN, KERN_CONSBUF, 0 },
{ "kern.audio", CTL_KERN, KERN_AUDIO, 0 },
{ "kern.cpustats", CTL_KERN, KERN_CPUSTATS, 0 },
{ "kern.pfstatus", CTL_KERN, KERN_PFSTATUS, 0 },
{ "kern.timeout_stats", CTL_KERN, KERN_TIMEOUT_STATS, 0 },
{ "kern.utc_offset", CTL_KERN, KERN_UTC_OFFSET, 0 },
{ "vm.vmmeter", CTL_VM, VM_METER, 0 },
{ "vm.loadavg", CTL_VM, VM_LOADAVG, 0 },
{ "vm.psstrings", CTL_VM, VM_PSSTRINGS, 0 },
{ "vm.uvmexp", CTL_VM, VM_UVMEXP, 0 },
{ "vm.swapencrypt", CTL_VM, VM_SWAPENCRYPT, 0 },
{ "vm.nkmempages", CTL_VM, VM_NKMEMPAGES, 0 },
{ "vm.anonmin", CTL_VM, VM_ANONMIN, 0 },
{ "vm.vtextmin", CTL_VM, VM_VTEXTMIN, 0 },
{ "vm.vnodemin", CTL_VM, VM_VNODEMIN, 0 },
{ "vm.maxslp", CTL_VM, VM_MAXSLP, 0 },
{ "vm.uspace", CTL_VM, VM_USPACE, 0 },
{ "vm.malloc_conf", CTL_VM, VM_MALLOC_CONF, 0 },
{ NULL, 0, 0, 0 },
};

View file

@ -0,0 +1,46 @@
/*
* Copyright (c) 2019-2021 Brian Callahan <bcallah@openbsd.org>
*
* Permission to use, copy, modify, and 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 <sys/types.h>
#include <sys/sysctl.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include "internal.h"
#include "../btop_tools.hpp"
int
sysctlbyname(const char *name, void *oldp, size_t *oldlenp,
void *newp, size_t newlen)
{
int i, mib[2];
for (i = 0; i < 132; i++) {
// for (i = 0; i < sizeof(sysctlnames) / sizeof(sysctlnames[0]); i++) {
if (!strcmp(name, sysctlnames[i].name)) {
mib[0] = sysctlnames[i].mib0;
mib[1] = sysctlnames[i].mib1;
return sysctl(mib, 2, oldp, oldlenp, newp, newlen);
}
}
errno = ENOENT;
return (-1);
}

View file

@ -0,0 +1,20 @@
/*
* Copyright (c) 2019 Brian Callahan <bcallah@openbsd.org>
*
* Permission to use, copy, modify, and 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 <sys/types.h>
#include <sys/sysctl.h>
extern int sysctlbyname(const char *, void *, size_t *, void *, size_t);