diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index de86eaf..faa7b5e 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -46,10 +46,10 @@ If btop++ is crashing at start the following steps could be helpful: (Extra helpful if compiled with `make OPTFLAGS="-O0 -g"`) -1. run `gdb btop` +1. run (linux): `gdb btop` (macos): `lldb btop` -2. `r` to run, wait for crash and press enter +2. `r` to run, wait for crash and press enter if prompted, CTRL+L to clear screen if needed. -3. `thread apply all bt` to get backtrace for all threads +3. (gdb): `thread apply all bt` (lldb): `bt all` to get backtrace for all threads 4. Copy and paste the backtrace here: diff --git a/.github/workflows/continuous-build-linux.yml b/.github/workflows/continuous-build-linux.yml index 38f3f2c..846aee8 100644 --- a/.github/workflows/continuous-build-linux.yml +++ b/.github/workflows/continuous-build-linux.yml @@ -52,7 +52,6 @@ jobs: - mipsel-linux-musln32 - mipsel-linux-musln32sf - mipsel-linux-muslsf - - or1k-linux-musl - powerpc-linux-musl - powerpc-linux-muslsf - powerpc64-linux-musl @@ -62,15 +61,17 @@ jobs: - riscv32-linux-musl - riscv64-linux-musl - s390x-linux-musl - - sh2-linux-musl - - sh2-linux-muslfdpic - - sh2eb-linux-musl - - sh2eb-linux-muslfdpic - - sh4-linux-musl - - sh4eb-linux-musl - x86_64-linux-musl - x86_64-linux-muslx32 + # - or1k-linux-musl + # - sh2-linux-musl + # - sh2-linux-muslfdpic + # - sh2eb-linux-musl + # - sh2eb-linux-muslfdpic + # - sh4-linux-musl + # - sh4eb-linux-musl + runs-on: ubuntu-latest container: muslcc/x86_64:${{ matrix.toolchain }} @@ -85,7 +86,7 @@ jobs: run: git init # [fix Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set).] - name: Build - run: make STATIC=true STRIP=true QUIET=true + run: make STATIC=true STRIP=true - name: Make executable run: chmod +x bin/* diff --git a/.github/workflows/continuous-build-macos.yml b/.github/workflows/continuous-build-macos.yml index b747e92..2cb5e4a 100644 --- a/.github/workflows/continuous-build-macos.yml +++ b/.github/workflows/continuous-build-macos.yml @@ -3,7 +3,7 @@ name: Continuous Build MacOS on: push: branches: - - OSX + - main tags-ignore: - '*.*' paths: @@ -17,21 +17,18 @@ on: jobs: build-osx: - runs-on: macos-latest + runs-on: macos-11 steps: - uses: actions/checkout@v2 - - name: Install build tools - run: | - git checkout OSX - name: Compile run: | - make CXX=g++-11 ARCH=x86_64 + make CXX=g++-11 ARCH=x86_64 STATIC=true STRIP=true GIT_HASH=$(git rev-parse --short "$GITHUB_SHA") - mv bin/btop bin/btop-x86_64-$GIT_HASH + mv bin/btop bin/btop-x86_64-BigSur-$GIT_HASH ls -alh bin - uses: actions/upload-artifact@v2 with: - name: btop-x86_64-macos + name: btop-x86_64-macos-BigSur path: 'bin/*' diff --git a/CHANGELOG.md b/CHANGELOG.md index 197882f..0ec004f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,87 @@ +## v1.1.3 + +* Added: New theme ayu, by @AlphaNecron + +* Added: New theme gruvbox_dark_v2, by @pietryszak + +* Fixed: Macos cpu coretemp for Intel, by @joske + +* Added: New theme OneDark, by @vtmx + +* Fixed: Fixed network graph scale int rollover + +* Fixed: Suspected possibility of very rare stall in Input::clear() + +## v1.1.2 + +* Fixed: SISEGV on macos Mojave, by @mgradowski + +* Fixed: Small optimizations and fixes to Mem::collect() and Input::get() + +* Fixed: Wrong unit for net_upload and net_download in config menu + +* Fixed: UTF-8 detection on macos + +* Fixed: coretemp iteration due to missing tempX_input, by @KFilipek + +* Fixed: coretemp ordering + +## v1.1.1 + +* Added: Partial static build (libgcc, libstdc++) for macos + +* Changed: Continuous build macos switched to OSX 11.6 (Big Sur) and partial static build + +* Changed: Release binaries for macos switched to OSX 12 (Monterey) and partial static build + +## v1.1.0 + +* Added: Support for OSX, by @joske and @aristocratos + +## v1.0.24 + +* Changed: Collection ordering + +* Fixed: Restore all escape seq mouse modes on exit + +* Fixed: SIGINT not cleaning up on exit + +## v1.0.23 + +* Fixed: Config parser missing first value when not including version header + +* Fixed: Vim keys menu lists selection + +* Fixed: Stall when clearing input queue on exit and queue is >1 + +* Fixed: Inconsistent behaviour of "q" key in the menus + +## v1.0.22 + +* Fixed: Bad values for disks and network on 32-bit + +## v1.0.21 + +* Fixed: Removed extra spaces in cpu name + +* Added: / as alternative bind for filter + +* Fixed: Security issue when running with SUID bit set + +## v1.0.20 + +* Added: Improved cpu sensor detection for Ryzen Mobile, by @adnanpri + +* Changed: Updated makefile + +* Changed: Regex for Fx::uncolor() changed to string search and replace + +* Changed: Removed all use of regex with dedicated string functions + +## v1.0.19 + +* Fixed: Makefile now tests compiler flag compatibility + ## v1.0.18 * Fixed: Makefile g++ -dumpmachine failure to get platform on some distros diff --git a/Makefile b/Makefile index c3b158c..f844c21 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ -#* Btop++ makefile v1.4 +#* Btop++ makefile v1.5 -BANNER = \n \033[38;5;196m██████\033[38;5;240m╗ \033[38;5;196m████████\033[38;5;240m╗ \033[38;5;196m██████\033[38;5;240m╗ \033[38;5;196m██████\033[38;5;240m╗\n \033[38;5;160m██\033[38;5;239m╔══\033[38;5;160m██\033[38;5;239m╗╚══\033[38;5;160m██\033[38;5;239m╔══╝\033[38;5;160m██\033[38;5;239m╔═══\033[38;5;160m██\033[38;5;239m╗\033[38;5;160m██\033[38;5;239m╔══\033[38;5;160m██\033[38;5;239m╗ \033[38;5;160m██\033[38;5;239m╗ \033[38;5;160m██\033[38;5;239m╗\n \033[38;5;124m██████\033[38;5;238m╔╝ \033[38;5;124m██\033[38;5;238m║ \033[38;5;124m██\033[38;5;238m║ \033[38;5;124m██\033[38;5;238m║\033[38;5;124m██████\033[38;5;238m╔╝ \033[38;5;124m██████\033[38;5;238m╗\033[38;5;124m██████\033[38;5;238m╗\n \033[38;5;88m██\033[38;5;237m╔══\033[38;5;88m██\033[38;5;237m╗ \033[38;5;88m██\033[38;5;237m║ \033[38;5;88m██\033[38;5;237m║ \033[38;5;88m██\033[38;5;237m║\033[38;5;88m██\033[38;5;237m╔═══╝ ╚═\033[38;5;88m██\033[38;5;237m╔═╝╚═\033[38;5;88m██\033[38;5;237m╔═╝\n \033[38;5;52m██████\033[38;5;236m╔╝ \033[38;5;52m██\033[38;5;236m║ ╚\033[38;5;52m██████\033[38;5;236m╔╝\033[38;5;52m██\033[38;5;236m║ ╚═╝ ╚═╝\n \033[38;5;235m╚═════╝ ╚═╝ ╚═════╝ ╚═╝ \033[1;3;38;5;240mMakefile v1.4\033[0m +BANNER = \n \033[38;5;196m██████\033[38;5;240m╗ \033[38;5;196m████████\033[38;5;240m╗ \033[38;5;196m██████\033[38;5;240m╗ \033[38;5;196m██████\033[38;5;240m╗\n \033[38;5;160m██\033[38;5;239m╔══\033[38;5;160m██\033[38;5;239m╗╚══\033[38;5;160m██\033[38;5;239m╔══╝\033[38;5;160m██\033[38;5;239m╔═══\033[38;5;160m██\033[38;5;239m╗\033[38;5;160m██\033[38;5;239m╔══\033[38;5;160m██\033[38;5;239m╗ \033[38;5;160m██\033[38;5;239m╗ \033[38;5;160m██\033[38;5;239m╗\n \033[38;5;124m██████\033[38;5;238m╔╝ \033[38;5;124m██\033[38;5;238m║ \033[38;5;124m██\033[38;5;238m║ \033[38;5;124m██\033[38;5;238m║\033[38;5;124m██████\033[38;5;238m╔╝ \033[38;5;124m██████\033[38;5;238m╗\033[38;5;124m██████\033[38;5;238m╗\n \033[38;5;88m██\033[38;5;237m╔══\033[38;5;88m██\033[38;5;237m╗ \033[38;5;88m██\033[38;5;237m║ \033[38;5;88m██\033[38;5;237m║ \033[38;5;88m██\033[38;5;237m║\033[38;5;88m██\033[38;5;237m╔═══╝ ╚═\033[38;5;88m██\033[38;5;237m╔═╝╚═\033[38;5;88m██\033[38;5;237m╔═╝\n \033[38;5;52m██████\033[38;5;236m╔╝ \033[38;5;52m██\033[38;5;236m║ ╚\033[38;5;52m██████\033[38;5;236m╔╝\033[38;5;52m██\033[38;5;236m║ ╚═╝ ╚═╝\n \033[38;5;235m╚═════╝ ╚═╝ ╚═════╝ ╚═╝ \033[1;3;38;5;240mMakefile v1.5\033[0m override BTOP_VERSION := $(shell head -n100 src/btop.cpp 2>/dev/null | grep "Version =" | cut -f2 -d"\"" || echo " unknown") override TIMESTAMP := $(shell date +%s 2>/dev/null || echo "0") @@ -26,9 +26,9 @@ ifneq ($(filter unknown Darwin, $(PLATFORM)),) ifeq ($(PLATFORM),apple) override PLATFORM := macos endif - ifeq ($(shell uname -v | grep ARM64 >/dev/null 2>&1; echo $$?),0) - ARCH ?= arm64 - endif +endif +ifeq ($(shell uname -v | grep ARM64 >/dev/null 2>&1; echo $$?),0) + ARCH ?= arm64 else ARCH ?= $(shell $(CXX) -dumpmachine | cut -d "-" -f 1) endif @@ -42,7 +42,10 @@ ifneq ($(PLATFORM) $(ARCH),macos arm64) endif ifeq ($(STATIC),true) - override ADDFLAGS += -DSTATIC_BUILD -static -static-libgcc -static-libstdc++ -Wl,--fatal-warnings + override ADDFLAGS += -static-libgcc -static-libstdc++ + ifneq ($(PLATFORM),macos) + override ADDFLAGS += -DSTATIC_BUILD -static -Wl,--fatal-warnings + endif endif ifeq ($(STRIP),true) @@ -57,7 +60,6 @@ else ifeq ($(shell command -v g++11 >/dev/null; echo $$?),0) else ifeq ($(shell command -v g++ >/dev/null; echo $$?),0) CXX := g++ endif - override CXX_VERSION := $(shell $(CXX) -dumpfullversion -dumpversion || echo 0) #? Try to make sure we are using GCC/G++ version 11 or later if not instructed to use g++-10 @@ -116,7 +118,7 @@ override GOODFLAGS := $(foreach flag,$(TESTFLAGS),$(strip $(shell echo "int main #? Flags, Libraries and Includes override REQFLAGS := -std=c++20 WARNFLAGS := -Wall -Wextra -pedantic -OPTFLAGS ?= -O2 -ftree-loop-vectorize -flto=$(THREADS) +OPTFLAGS := -O2 -ftree-loop-vectorize -flto=$(THREADS) LDCXXFLAGS := -pthread -D_FORTIFY_SOURCE=2 -D_GLIBCXX_ASSERTIONS $(GOODFLAGS) $(ADDFLAGS) override CXXFLAGS += $(REQFLAGS) $(LDCXXFLAGS) $(OPTFLAGS) $(WARNFLAGS) override LDFLAGS += $(LDCXXFLAGS) $(OPTFLAGS) $(WARNFLAGS) @@ -226,12 +228,7 @@ $(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(SRCEXT) @sleep 0.3 2>/dev/null || true @TSTAMP=$$(date +%s 2>/dev/null || echo "0") @$(QUIET) || printf "\033[1;97mCompiling $<\033[0m\n" - @$(CXX) $(CXXFLAGS) $(INC) -c -o $@ $< || exit 1 - @$(CXX) $(CXXFLAGS) $(INC) -MM $(SRCDIR)/$*.$(SRCEXT) > $(BUILDDIR)/$*.$(DEPEXT) >/dev/null || exit 1 - @cp -f $(BUILDDIR)/$*.$(DEPEXT) $(BUILDDIR)/$*.$(DEPEXT).tmp - @sed -e 's|.*:|$(BUILDDIR)/$*.$(OBJEXT):|' < $(BUILDDIR)/$*.$(DEPEXT).tmp > $(BUILDDIR)/$*.$(DEPEXT) - @sed -e 's/.*://' -e 's/\\$$//' < $(BUILDDIR)/$*.$(DEPEXT).tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $(BUILDDIR)/$*.$(DEPEXT) - @rm -f $(BUILDDIR)/$*.$(DEPEXT).tmp + @$(CXX) $(CXXFLAGS) $(INC) -MMD -c -o $@ $< || exit 1 @printf "\033[1;92m-> \033[1;37m$@ \033[100D\033[35C\033[1;93m(\033[1;97m$$(du -ah $@ | cut -f1)iB\033[1;93m) \033[92m(\033[97m$$($(DATE_CMD) -d @$$(expr $$(date +%s 2>/dev/null || echo "0") - $${TSTAMP} 2>/dev/null) -u +%Mm:%Ss 2>/dev/null | sed 's/^00m://' || echo '')\033[92m)\033[0m\n" #? Non-File Targets diff --git a/README.md b/README.md index 42c58b0..f52c2a3 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,8 @@ ![Linux](https://img.shields.io/badge/-Linux-grey?logo=linux) +![OSX](https://img.shields.io/badge/-OSX-black?logo=apple) +![FreeBSD](https://img.shields.io/badge/-FreeBSD-red?logo=freebsd) ![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) @@ -12,14 +14,11 @@ [![Sponsor](https://img.shields.io/badge/-Sponsor-red?logo=github)](https://github.com/sponsors/aristocratos) [![Coffee](https://img.shields.io/badge/-Buy%20me%20a%20Coffee-grey?logo=Ko-fi)](https://ko-fi.com/aristocratos) [![btop](https://snapcraft.io/btop/badge.svg)](https://snapcraft.io/btop) -[![Continuous Build Linux](https://github.com/aristocratos/btop/actions/workflows/continuous-build.yml/badge.svg)](https://github.com/aristocratos/btop/actions) +[![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) - ## Index - - * [News](#news) * [Documents](#documents) * [Description](#description) @@ -29,9 +28,10 @@ * [Prerequisites](#prerequisites) (Read this if you are having issues!) * [Screenshots](#screenshots) * [Keybindings](#help-menu) -* [Installation](#installation) -* [Manual compilation](#compilation) -* [Install the snap](#install-the-snap) +* [Installation Linux/OSX](#installation) +* [Compilation Linux](#compilation-linux) +* [Compilation OSX](#compilation-osx) +* [Installing the snap](#installing-the-snap) * [Configurability](#configurability) * [License](#license) @@ -39,9 +39,48 @@ ### Under development +##### 13 November 2021 + +Release v1.1.0 with OSX support. Binaries in [continuous-build-macos](https://github.com/aristocratos/btop/actions/workflows/continuous-build-macos.yml) are only x86 for now. +Macos binaries + installer are included for both x86 and ARM64 (Apple Silicon) in the releases. + +Big thank you to [@joske](https://github.com/joske) who wrote the vast majority of the implementation! + +
+More... + +##### 30 October 2021 + +Work on the OSX and FreeBSD branches, both initiated and mostly worked on by [@joske](https://github.com/joske), will likely be completed in the coming weeks. +The OSX branch has some memory leaks that needs to be sorted out and both have some issues with the processes cpu usage calculation and other smaller issues that needs fixing. + +If you want to help out, test for bugs/fix bugs or just try out the branches: + +**OSX** +```bash +# Install and use Homebrew or MacPorts package managers for easy dependency installation +brew install coreutils make gcc@11 +git clone https://github.com/aristocratos/btop.git +cd btop +git checkout OSX +gmake +``` + +**FreeBSD** +```bash +sudo pkg install gmake gcc11 coreutils git +git clone https://github.com/aristocratos/btop.git +cd btop +git checkout freebsd +gmake +``` + +Note that GNU make (`gmake`) is recommended but not required for OSX but it is required on FreeBSD. + + ##### 6 October 2021 -OsX development have been started by @joske , big thanks :) +OsX development have been started by [@joske](https://github.com/joske), big thanks :) See branch [OSX](https://github.com/aristocratos/btop/tree/OSX) for current progress. ##### 18 September 2021 @@ -68,6 +107,8 @@ Windows support is not in the plans as of now, but if anyone else wants to take This project is gonna take some time until it has complete feature parity with bpytop, since all system information gathering will have to be written from scratch without any external libraries. And will need some help in the form of code contributions to get complete support for BSD and OSX. +
+ ## Documents **[CHANGELOG.md](CHANGELOG.md)** @@ -176,9 +217,11 @@ Also needs a UTF8 locale and a font that covers: ## Installation -**Binary release (statically compiled with musl, for kernel 2.6.39 and newer)** +**Binaries for Linux are statically compiled with musl and works on kernel 2.6.39 and newer** -1. **Download btop-(VERSION)-(PLATFORM)-(ARCH).tbz from [latest release](https://github.com/aristocratos/btop/releases/latest) and unpack to a new folder** +1. **Download btop-(VERSION)-(ARCH)-(PLATFORM).tbz from [latest release](https://github.com/aristocratos/btop/releases/latest) and unpack to a new folder** + + **Notice! Use x86_64 for 64-bit x86 systems, i486 and i686 are 32-bit!** 2. **Install (from created folder)** @@ -232,7 +275,14 @@ Also needs a UTF8 locale and a font that covers: sudo zypper in btop ``` -## Compilation +**Binary release on Homebrew (macOS (x86_64 & ARM64) / Linux (x86_64))** + +* **[Homebrew](https://formulae.brew.sh/formula/btop)** + ```bash + brew install btop + ``` + +## Compilation Linux Needs GCC 10 or higher, (GCC 11 or above strongly recommended for better CPU efficiency in the compiled binary). @@ -324,7 +374,94 @@ Also needs a UTF8 locale and a font that covers: make help ``` -## Install the snap +## Compilation OSX + + Needs GCC 10 or higher, (GCC 11 or above strongly recommended for better CPU efficiency in the compiled binary). + + The makefile also needs GNU coreutils and `sed`. + + Install and use Homebrew or MacPorts package managers for easy dependency installation + +1. **Install dependencies (example for Homebrew)** + + ``` bash + brew install coreutils make gcc@11 + ``` + +2. **Clone repository** + + ``` bash + git clone https://github.com/aristocratos/btop.git + cd btop + ``` + +3. **Compile** + + Append `STATIC=true` to `make` command for static compilation (only libgcc and libstdc++ will be static!). + + Append `QUIET=true` for less verbose output. + + Append `STRIP=true` to force stripping of debug symbols (adds `-s` linker flag). + + Append `ARCH=` to manually set the target architecture. + If omitted the makefile uses the machine triple (output of `-dumpmachine` compiler parameter) to detect the target system. + + Use `ADDFLAGS` variable for appending flags to both compiler and linker. + + For example: `ADDFLAGS=-march=native` might give a performance boost if compiling only for your own system. + + ``` bash + gmake + ``` + +4. **Install** + + Append `PREFIX=/target/dir` to set target, default: `/usr/local` + + Notice! Only use "sudo" when installing to a NON user owned directory. + + ``` bash + sudo gmake install + ``` + +5. **(Recommended) Set suid bit to make btop always run as root (or other user)** + + 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` + + ``` bash + sudo gmake setuid + ``` + +* **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 + ``` + + +## Installing the snap [![btop](https://snapcraft.io/btop/badge.svg)](https://snapcraft.io/btop) * **Install the snap** diff --git a/src/btop.cpp b/src/btop.cpp index 70f0c11..50527fd 100644 --- a/src/btop.cpp +++ b/src/btop.cpp @@ -31,6 +31,9 @@ tab-size = 4 #include #include #include +#ifdef __APPLE__ + #include +#endif #include #include @@ -56,7 +59,7 @@ namespace Global { {"#801414", "██████╔╝ ██║ ╚██████╔╝██║ ╚═╝ ╚═╝"}, {"#000000", "╚═════╝ ╚═╝ ╚═════╝ ╚═╝"}, }; - const string Version = "1.0.18"; + const string Version = "1.1.3"; int coreCount; string overlay; @@ -67,6 +70,7 @@ namespace Global { string fg_green = "\x1b[1;92m"; string fg_red = "\x1b[0;91m"; + uid_t real_uid, set_uid; fs::path self_path; @@ -81,6 +85,8 @@ namespace Global { atomic resized (false); atomic quitting (false); + atomic should_quit (false); + atomic should_sleep (false); atomic _runner_started (false); bool arg_tty = false; @@ -88,7 +94,6 @@ namespace Global { int arg_preset = -1; } - //* A simple argument parser void argumentParser(const int& argc, char **argv) { for(int i = 1; i < argc; i++) { @@ -180,7 +185,7 @@ void term_resize(bool force) { if (Input::poll()) { auto key = Input::get(); if (key == "q") - exit(0); + clean_quit(0); else if (is_in(key, "1", "2", "3", "4")) { Config::current_preset = -1; Config::toggle_box(all_boxes.at(std::stoi(key) - 1)); @@ -217,7 +222,6 @@ void clean_quit(int sig) { } Config::write(); - Input::clear(); //? Wait for any remaining Tools::atomic_lock destructors to finish for max 1000ms for (int i = 0; Tools::active_locks > 0 and i < 100; i++) { @@ -225,6 +229,7 @@ void clean_quit(int sig) { } if (Term::initialized) { + Input::clear(); Term::restore(); } @@ -265,10 +270,24 @@ void _exit_handler() { void _signal_handler(const int sig) { switch (sig) { case SIGINT: - clean_quit(0); + if (Runner::active) { + Global::should_quit = true; + Runner::stopping = true; + Input::interrupt = true; + } + else { + clean_quit(0); + } break; case SIGTSTP: - _sleep(); + if (Runner::active) { + Global::should_sleep = true; + Runner::stopping = true; + Input::interrupt = true; + } + else { + _sleep(); + } break; case SIGCONT: _resume(); @@ -306,10 +325,22 @@ namespace Runner { pthread_mutex_t& pt_mutex; public: int status; - thread_lock(pthread_mutex_t& mtx) : pt_mutex(mtx) { pthread_mutex_init(&mtx, NULL); status = pthread_mutex_lock(&pt_mutex); } + thread_lock(pthread_mutex_t& mtx) : pt_mutex(mtx) { pthread_mutex_init(&pt_mutex, NULL); status = pthread_mutex_lock(&pt_mutex); } ~thread_lock() { if (status == 0) pthread_mutex_unlock(&pt_mutex); } }; + //* Wrapper for raising priviliges when using SUID bit + class gain_priv { + int status = -1; + public: + gain_priv() { + if (Global::real_uid != Global::set_uid) this->status = seteuid(Global::set_uid); + } + ~gain_priv() { + if (status == 0) status = seteuid(Global::real_uid); + } + }; + string output; string empty_bg; bool pause_output = false; @@ -362,10 +393,10 @@ namespace Runner { //? ------------------------------- Secondary thread: async launcher and drawing ---------------------------------- void * _runner(void * _) { (void)_; - //? Block all signals in this thread to avoid deadlock from any signal handlers trying to stop this thread + //? Block some signals in this thread to avoid deadlock from any signal handlers trying to stop this thread sigemptyset(&mask); - sigaddset(&mask, SIGINT); - sigaddset(&mask, SIGTSTP); + // sigaddset(&mask, SIGINT); + // sigaddset(&mask, SIGTSTP); sigaddset(&mask, SIGWINCH); sigaddset(&mask, SIGTERM); pthread_sigmask(SIG_BLOCK, &mask, NULL); @@ -397,6 +428,9 @@ namespace Runner { //? Atomic lock used for blocking non thread-safe actions in main thread atomic_lock lck(active); + //? Set effective user if SUID bit is set + gain_priv powers{}; + auto& conf = current_conf; //! DEBUG stats @@ -410,44 +444,23 @@ namespace Runner { //* Run collection and draw functions for all boxes try { - //? PROC - if (v_contains(conf.boxes, "proc")) { + //? CPU + if (v_contains(conf.boxes, "cpu")) { try { - if (Global::debug) debug_timer("proc", collect_begin); + if (Global::debug) debug_timer("cpu", collect_begin); //? Start collect - auto proc = Proc::collect(conf.no_update); + auto cpu = Cpu::collect(conf.no_update); - if (Global::debug) debug_timer("proc", draw_begin); + if (Global::debug) debug_timer("cpu", draw_begin); //? Draw box - if (not pause_output) output += Proc::draw(proc, conf.force_redraw, conf.no_update); + if (not pause_output) output += Cpu::draw(cpu, conf.force_redraw, conf.no_update); - if (Global::debug) debug_timer("proc", draw_done); + if (Global::debug) debug_timer("cpu", draw_done); } catch (const std::exception& e) { - throw std::runtime_error("Proc:: -> " + (string)e.what()); - } - } - - - //? NET - if (v_contains(conf.boxes, "net")) { - try { - if (Global::debug) debug_timer("net", collect_begin); - - //? Start collect - auto net = Net::collect(conf.no_update); - - if (Global::debug) debug_timer("net", draw_begin); - - //? Draw box - if (not pause_output) output += Net::draw(net, conf.force_redraw, conf.no_update); - - if (Global::debug) debug_timer("net", draw_done); - } - catch (const std::exception& e) { - throw std::runtime_error("Net:: -> " + (string)e.what()); + throw std::runtime_error("Cpu:: -> " + (string)e.what()); } } @@ -471,23 +484,43 @@ namespace Runner { } } - //? CPU - if (v_contains(conf.boxes, "cpu")) { + //? NET + if (v_contains(conf.boxes, "net")) { try { - if (Global::debug) debug_timer("cpu", collect_begin); + if (Global::debug) debug_timer("net", collect_begin); //? Start collect - auto cpu = Cpu::collect(conf.no_update); + auto net = Net::collect(conf.no_update); - if (Global::debug) debug_timer("cpu", draw_begin); + if (Global::debug) debug_timer("net", draw_begin); //? Draw box - if (not pause_output) output += Cpu::draw(cpu, conf.force_redraw, conf.no_update); + if (not pause_output) output += Net::draw(net, conf.force_redraw, conf.no_update); - if (Global::debug) debug_timer("cpu", draw_done); + if (Global::debug) debug_timer("net", draw_done); } catch (const std::exception& e) { - throw std::runtime_error("Cpu:: -> " + (string)e.what()); + throw std::runtime_error("Net:: -> " + (string)e.what()); + } + } + + //? PROC + if (v_contains(conf.boxes, "proc")) { + try { + if (Global::debug) debug_timer("proc", collect_begin); + + //? Start collect + auto proc = Proc::collect(conf.no_update); + + if (Global::debug) debug_timer("proc", draw_begin); + + //? Draw box + if (not pause_output) output += Proc::draw(proc, conf.force_redraw, conf.no_update); + + if (Global::debug) debug_timer("proc", draw_done); + } + catch (const std::exception& e) { + throw std::runtime_error("Proc:: -> " + (string)e.what()); } } } @@ -543,7 +576,6 @@ namespace Runner { << Term::sync_end << flush; } //* ----------------------------------------------- THREAD LOOP ----------------------------------------------- - pthread_exit(NULL); } //? ------------------------------------------ Secondary thread end ----------------------------------------------- @@ -558,7 +590,7 @@ namespace Runner { pthread_cancel(Runner::runner_id); if (pthread_create(&Runner::runner_id, NULL, &Runner::_runner, NULL) != 0) { Global::exit_error_msg = "Failed to re-create _runner thread!"; - exit(1); + clean_quit(1); } } if (stopping or Global::resized) return; @@ -597,7 +629,7 @@ namespace Runner { if (ret != EBUSY and not Global::quitting) { if (active) active = false; Global::exit_error_msg = "Runner thread died unexpectedly!"; - exit(1); + clean_quit(1); } else if (ret == EBUSY) { atomic_wait_for(active, true, 5000); @@ -608,7 +640,7 @@ namespace Runner { } else { Global::exit_error_msg = "No response from Runner thread, quitting!"; - exit(1); + clean_quit(1); } } thread_trigger(); @@ -628,6 +660,17 @@ int main(int argc, char **argv) { Global::start_time = time_s(); + //? Save real and effective userid's and drop priviliges until needed if running with SUID bit set + Global::real_uid = getuid(); + Global::set_uid = geteuid(); + if (Global::real_uid != Global::set_uid) { + if (seteuid(Global::real_uid) != 0) { + Global::real_uid = Global::set_uid; + Global::exit_error_msg = "Failed to change effective user ID. Unset btop SUID bit to ensure security on this system. Quitting!"; + clean_quit(1); + } + } + //? Call argument parser if launched with arguments if (argc > 1) argumentParser(argc, argv); @@ -727,12 +770,34 @@ int main(int argc, char **argv) { } } + #ifdef __APPLE__ + if (found.empty()) { + CFLocaleRef cflocale = CFLocaleCopyCurrent(); + CFStringRef id_value = (CFStringRef)CFLocaleGetValue(cflocale, kCFLocaleIdentifier); + auto loc_id = CFStringGetCStringPtr(id_value, kCFStringEncodingUTF8); + CFRelease(cflocale); + std::string cur_locale = (loc_id != nullptr ? loc_id : ""); + if (cur_locale.empty()) { + Logger::warning("No UTF-8 locale detected! Some symbols might not display correctly."); + } + else if (std::setlocale(LC_ALL, string(cur_locale + ".UTF-8").c_str()) != NULL) { + Logger::debug("Setting LC_ALL=" + cur_locale + ".UTF-8"); + } + else if(std::setlocale(LC_ALL, "en_US.UTF-8") != NULL) { + Logger::debug("Setting LC_ALL=en_US.UTF-8"); + } + else { + Logger::warning("Failed to set macos locale, continuing anyway."); + } + } + #else if (found.empty() and Global::utf_force) Logger::warning("No UTF-8 locale detected! Forcing start with --utf-force argument."); else if (found.empty()) { Global::exit_error_msg = "No UTF-8 locale detected!\nUse --utf-force argument to force start if you're sure your terminal can handle it."; clean_quit(1); } + #endif else if (not set_failure) Logger::debug("Setting LC_ALL=" + found); } @@ -792,7 +857,7 @@ int main(int argc, char **argv) { Runner::thread_sem_init(); if (pthread_create(&Runner::runner_id, NULL, &Runner::_runner, NULL) != 0) { Global::exit_error_msg = "Failed to create _runner thread!"; - exit(1); + clean_quit(1); } else { Global::_runner_started = true; @@ -829,7 +894,9 @@ int main(int argc, char **argv) { try { while (not true not_eq not false) { //? Check for exceptions in secondary thread and exit with fail signal if true - if (Global::thread_exception) exit(1); + if (Global::thread_exception) clean_quit(1); + else if (Global::should_quit) clean_quit(0); + else if (Global::should_sleep) { Global::should_sleep = false; _sleep(); } //? Make sure terminal size hasn't changed (in case of SIGWINCH not working properly) term_resize(); @@ -884,7 +951,7 @@ int main(int argc, char **argv) { } catch (const std::exception& e) { Global::exit_error_msg = "Exception in main loop -> " + (string)e.what(); - exit(1); + clean_quit(1); } } diff --git a/src/btop_config.cpp b/src/btop_config.cpp index ca3e66a..66069d7 100644 --- a/src/btop_config.cpp +++ b/src/btop_config.cpp @@ -479,7 +479,7 @@ namespace Config { } catch (const std::exception& e) { Global::exit_error_msg = "Exception during Config::unlock() : " + (string)e.what(); - exit(1); + clean_quit(1); } locked = false; @@ -530,9 +530,7 @@ namespace Config { vector valid_names; for (auto &n : descriptions) valid_names.push_back(n[0]); - string v_string; - getline(cread, v_string, '\n'); - if (not s_contains(v_string, Global::Version)) + if (string v_string; cread.peek() != '#' or (getline(cread, v_string, '\n') and not s_contains(v_string, Global::Version))) write_new = true; while (not cread.eof()) { cread >> std::ws; @@ -589,6 +587,7 @@ namespace Config { void write() { if (conf_file.empty() or not write_new) return; Logger::debug("Writing new config file"); + if (geteuid() != Global::real_uid and seteuid(Global::real_uid) != 0) return; std::ofstream cwrite(conf_file, std::ios::trunc); if (cwrite.good()) { cwrite << "#? Config file for btop v. " << Global::Version; diff --git a/src/btop_draw.cpp b/src/btop_draw.cpp index bc64dc9..a309834 100644 --- a/src/btop_draw.cpp +++ b/src/btop_draw.cpp @@ -947,8 +947,8 @@ namespace Net { const string title_left = Theme::c("net_box") + Fx::ub + Symbols::title_left; const string title_right = Theme::c("net_box") + Fx::ub + Symbols::title_right; const int i_size = min((int)selected_iface.size(), 10); - const long long down_max = (net_auto ? graph_max.at("download") : (long long)(Config::getI("net_download") << 20) / 8); - const long long up_max = (net_auto ? graph_max.at("upload") : (long long)(Config::getI("net_upload") << 20) / 8); + const long long down_max = (net_auto ? graph_max.at("download") : ((long long)(Config::getI("net_download")) << 20) / 8); + const long long up_max = (net_auto ? graph_max.at("upload") : ((long long)(Config::getI("net_upload")) << 20) / 8); //* Redraw elements not needed to be updated every cycle if (redraw) { diff --git a/src/btop_input.cpp b/src/btop_input.cpp index 7d6be33..09a366e 100644 --- a/src/btop_input.cpp +++ b/src/btop_input.cpp @@ -97,7 +97,7 @@ namespace Input { string get() { string key; while (cin.rdbuf()->in_avail() > 0 and key.size() < 100) key += cin.get(); - if (cin.rdbuf()->in_avail() > 0) cin.ignore(cin.rdbuf()->in_avail()); + if (cin.rdbuf()->in_avail() > 0) clear(); if (not key.empty()) { //? Remove escape code prefix if present if (key.substr(0, 2) == Fx::e) { @@ -107,14 +107,14 @@ namespace Input { if (key.starts_with("[<")) { std::string_view key_view = key; string mouse_event; - if (key_view.starts_with("[<0;") and key_view.ends_with('M')) { + if (key_view.starts_with("[<0;") and key_view.find('M') != std::string_view::npos) { mouse_event = "mouse_click"; key_view.remove_prefix(4); } - else if (key_view.starts_with("[<0;") and key_view.ends_with('m')) { - mouse_event = "mouse_release"; - key_view.remove_prefix(4); - } + // else if (key_view.starts_with("[<0;") and key_view.ends_with('m')) { + // mouse_event = "mouse_release"; + // key_view.remove_prefix(4); + // } else if (key_view.starts_with("[<64;")) { mouse_event = "mouse_scroll_up"; key_view.remove_prefix(5); @@ -177,7 +177,12 @@ namespace Input { } void clear() { - if (cin.rdbuf()->in_avail() > 0) cin.ignore(SSmax); + if (auto first_num = cin.rdbuf()->in_avail(); first_num > 0) { + while (cin.rdbuf()->in_avail() == first_num) { + if (first_num-- <= 0) break; + cin.ignore(1); + } + } } void process(const string& key) { @@ -268,7 +273,7 @@ namespace Input { cur_i = 0; Config::set("proc_sorting", Proc::sort_vector.at(cur_i)); } - else if (key == "f") { + else if (is_in(key, "f", "/")) { Config::flip("proc_filtering"); Proc::filter = { Config::getS("proc_filter") }; old_filter = Proc::filter.text; diff --git a/src/btop_menu.cpp b/src/btop_menu.cpp index 500a86e..ef159a4 100644 --- a/src/btop_menu.cpp +++ b/src/btop_menu.cpp @@ -126,7 +126,7 @@ namespace Menu { {"z", "Toggle totals reset for current network device"}, {"a", "Toggle auto scaling for the network graphs."}, {"y", "Toggle synced scaling mode for network graphs."}, - {"f", "To enter a process filter."}, + {"f, /", "To enter a process filter."}, {"delete", "Clear any entered filter."}, {"c", "Toggle per-core cpu usage of processes."}, {"r", "Reverse sorting order in processes box."}, @@ -486,13 +486,13 @@ namespace Menu { {"net_download", "Fixed network graph download value.", "", - "Value in Mebibytes, default \"100\".", + "Value in Mebibits, default \"100\".", "", "Can be toggled with auto button."}, {"net_upload", "Fixed network graph upload value.", "", - "Value in Mebibytes, default \"100\".", + "Value in Mebibits, default \"100\".", "", "Can be toggled with auto button."}, {"net_auto", @@ -892,10 +892,7 @@ namespace Menu { }; } } - else if (key == "q") { - exit(0); - } - else if (is_in(key, "escape", "m", "mouse_click")) { + else if (is_in(key, "escape", "q", "m", "mouse_click")) { return Closed; } else if (key.starts_with("button_")) { @@ -916,7 +913,7 @@ namespace Menu { currentMenu = Menus::Help; return Switch; case Quit: - exit(0); + clean_quit(0); } } else if (is_in(key, "down", "tab", "mouse_scroll_down", "j")) { @@ -1142,8 +1139,8 @@ namespace Menu { auto& optList = optionsList.at(option).get(); int i = v_index(optList, Config::getS(option)); - if (key == "right" and ++i >= (int)optList.size()) i = 0; - else if (key == "left" and --i < 0) i = optList.size() - 1; + if ((key == "right" or (vim_keys and key == "l")) and ++i >= (int)optList.size()) i = 0; + else if ((key == "left" or (vim_keys and key == "h")) and --i < 0) i = optList.size() - 1; Config::set(option, optList.at(i)); if (option == "color_theme") diff --git a/src/btop_shared.hpp b/src/btop_shared.hpp index 5833d49..9fb52d1 100644 --- a/src/btop_shared.hpp +++ b/src/btop_shared.hpp @@ -27,12 +27,15 @@ tab-size = 4 #include #include #include +#include using std::string, std::vector, std::deque, robin_hood::unordered_flat_map, std::atomic, std::array, std::tuple; void term_resize(bool force=false); void banner_gen(); +extern void clean_quit(int sig); + namespace Global { extern const vector> Banner_src; extern const string Version; @@ -43,6 +46,7 @@ namespace Global { extern atomic resized; extern string overlay; extern string clock; + extern uid_t real_uid, set_uid; } namespace Runner { diff --git a/src/btop_tools.cpp b/src/btop_tools.cpp index aab8266..8ab9212 100644 --- a/src/btop_tools.cpp +++ b/src/btop_tools.cpp @@ -23,10 +23,10 @@ tab-size = 4 #include #include #include +#include #include #include -#include #include #include @@ -50,7 +50,6 @@ namespace Term { atomic width = 0; atomic height = 0; string current_tty; - char* custombuf; namespace { struct termios initial_settings; @@ -126,9 +125,6 @@ namespace Term { linebuffered(false); refresh(); - //? Set 1MB buffer for cout - std::cout.rdbuf()->pubsetbuf(custombuf, 1048576); - cout << alt_screen << hide_cursor << mouse_on << flush; Global::resized = false; } @@ -147,6 +143,25 @@ namespace Term { //? --------------------------------------------------- FUNCTIONS ----------------------------------------------------- +namespace Fx { + string uncolor(const string& s) { + string out = s; + for (size_t offset = 0, start_pos = 0, end_pos = 0, next_pos = 0;;) { + if ((start_pos = next_pos > 0 ? next_pos : out.find('\x1b', offset)) == string::npos) + break; + offset = ++start_pos; + if ((end_pos = out.find('m', offset)) == string::npos) + break; + else if (next_pos = out.find('\x1b', offset); not isdigit(out[end_pos - 1]) or end_pos - start_pos > next_pos - start_pos) + continue; + out.replace(start_pos, end_pos - start_pos, ""); + next_pos = 0; + } + out.shrink_to_fit(); + return out; + } +} + namespace Tools { atomic active_locks (0); @@ -395,6 +410,18 @@ namespace Logger { size_t loglevel; fs::path logfile; + //* Wrapper for lowering priviliges if using SUID bit and currently isn't using real userid + class lose_priv { + int status = -1; + public: + lose_priv() { + if (geteuid() != Global::real_uid) this->status = seteuid(Global::real_uid); + } + ~lose_priv() { + if (status == 0) status = seteuid(Global::set_uid); + } + }; + void set(const string& level) { loglevel = v_index(log_levels, level); } @@ -402,6 +429,7 @@ namespace Logger { void log_write(const size_t level, const string& msg) { if (loglevel < level or logfile.empty()) return; atomic_lock lck(busy, true); + lose_priv neutered{}; std::error_code ec; try { if (fs::exists(logfile) and fs::file_size(logfile, ec) > 1024 << 10 and not ec) { diff --git a/src/btop_tools.hpp b/src/btop_tools.hpp index 9cc9e82..42ab659 100644 --- a/src/btop_tools.hpp +++ b/src/btop_tools.hpp @@ -21,7 +21,6 @@ tab-size = 4 #include #include #include -#include #include #include #include @@ -29,8 +28,16 @@ tab-size = 4 #include #include #include +#include +#ifndef HOST_NAME_MAX + #ifdef __APPLE__ + #define HOST_NAME_MAX 255 + #else + #define HOST_NAME_MAX 64 + #endif +#endif -using std::string, std::vector, std::atomic, std::to_string, std::regex, std::tuple, std::array; +using std::string, std::vector, std::atomic, std::to_string, std::tuple, std::array; #ifndef HOST_NAME_MAX #if defined(__APPLE__) @@ -64,14 +71,8 @@ namespace Fx { //* Reset text effects and restore theme foregrund and background color extern string reset; - //* Regex for matching color, style and cursor move escape sequences - const regex escape_regex("\033\\[\\d+;?\\d?;?\\d*;?\\d*;?\\d*(m|f|s|u|C|D|A|B){1}"); - - //* Regex for matching only color and style escape sequences - const regex color_regex("\033\\[\\d+;?\\d?;?\\d*;?\\d*;?\\d*(m){1}"); - //* Return a string with all colors and text styling removed - inline string uncolor(const string& s) { return regex_replace(s, color_regex, ""); } + string uncolor(const string& s); } @@ -114,7 +115,7 @@ namespace Term { const string clear_end = Fx::e + "0J"; const string clear_begin = Fx::e + "1J"; const string mouse_on = Fx::e + "?1002h" + Fx::e + "?1015h" + Fx::e + "?1006h"; //? Enable reporting of mouse position on click and release - const string mouse_off = Fx::e + "?1002l"; + const string mouse_off = Fx::e + "?1002l" + Fx::e + "?1015l" + Fx::e + "?1006l"; const string mouse_direct_on = Fx::e + "?1003h"; //? Enable reporting of mouse position at any movement const string mouse_direct_off = Fx::e + "?1003l"; const string sync_start = Fx::e + "?2026h"; //? Start of terminal synchronized output diff --git a/src/linux/btop_collect.cpp b/src/linux/btop_collect.cpp index 2a5a31d..bf869df 100644 --- a/src/linux/btop_collect.cpp +++ b/src/linux/btop_collect.cpp @@ -21,7 +21,6 @@ tab-size = 4 #include #include #include -#include #include #include #include @@ -217,9 +216,9 @@ namespace Cpu { name += n + ' '; } name.pop_back(); - for (const auto& reg : {regex("Processor"), regex("CPU"), regex("\\(R\\)"), regex("\\(TM\\)"), regex("Intel"), - regex("AMD"), regex("Core"), regex("\\d?\\.?\\d+[mMgG][hH][zZ]")}) { - name = std::regex_replace(name, reg, ""); + for (const auto& replace : {"Processor", "CPU", "(R)", "(TM)", "Intel", "AMD", "Core"}) { + name = s_replace(name, replace, ""); + name = s_replace(name, " ", " "); } name = trim(name); } @@ -241,20 +240,36 @@ namespace Cpu { if (s_contains(add_path, "coretemp")) got_coretemp = true; - if (fs::exists(add_path / "temp1_input")) { - search_paths.push_back(add_path); + for (const auto & file : fs::directory_iterator(add_path)) { + if (string(file.path().filename()) == "device") { + for (const auto & dev_file : fs::directory_iterator(file.path())) { + string dev_filename = dev_file.path().filename(); + if (dev_filename.starts_with("temp") and dev_filename.ends_with("_input")) { + search_paths.push_back(file.path()); + break; + } + } + } + + string filename = file.path().filename(); + if (filename.starts_with("temp") and filename.ends_with("_input")) { + search_paths.push_back(add_path); + break; + } } - else if (fs::exists(add_path / "device/temp1_input")) - search_paths.push_back(add_path / "device"); } } if (not got_coretemp and fs::exists(fs::path("/sys/devices/platform/coretemp.0/hwmon"))) { for (auto& d : fs::directory_iterator(fs::path("/sys/devices/platform/coretemp.0/hwmon"))) { fs::path add_path = fs::canonical(d.path()); - if (fs::exists(d.path() / "temp1_input") and not v_contains(search_paths, add_path)) { - search_paths.push_back(add_path); - got_coretemp = true; + for (const auto & file : fs::directory_iterator(add_path)) { + string filename = file.path().filename(); + if (filename.starts_with("temp") and filename.ends_with("_input") and not v_contains(search_paths, add_path)) { + search_paths.push_back(add_path); + got_coretemp = true; + break; + } } } } @@ -262,9 +277,17 @@ namespace Cpu { if (not search_paths.empty()) { for (const auto& path : search_paths) { const string pname = readfile(path / "name", path.filename()); - for (int i = 1; fs::exists(path / string("temp" + to_string(i) + "_input")); i++) { - const string basepath = path / string("temp" + to_string(i) + "_"); - const string label = readfile(fs::path(basepath + "label"), "temp" + to_string(i)); + for (const auto & file : fs::directory_iterator(path)) { + const string file_suffix = "input"; + const int file_id = atoi(file.path().filename().c_str() + 4); // skip "temp" prefix + string file_path = file.path(); + + if (!s_contains(file_path, file_suffix)) { + continue; + } + + const string basepath = file_path.erase(file_path.find(file_suffix), file_suffix.length()); + const string label = readfile(fs::path(basepath + "label"), "temp" + to_string(file_id)); const string sensor_name = pname + "/" + label; const int64_t temp = stol(readfile(fs::path(basepath + "input"), "0")) / 1000; const int64_t high = stol(readfile(fs::path(basepath + "max"), "80000")) / 1000; @@ -310,10 +333,19 @@ namespace Cpu { } catch (...) {} - if (not got_coretemp or core_sensors.empty()) cpu_temp_only = true; + if (not got_coretemp or core_sensors.empty()) { + cpu_temp_only = true; + } + else { + rng::sort(core_sensors, rng::less{}); + rng::stable_sort(core_sensors, [](const auto& a, const auto& b){ + return a.size() < b.size(); + }); + } + if (cpu_sensor.empty() and not found_sensors.empty()) { for (const auto& [name, sensor] : found_sensors) { - if (s_contains(str_to_lower(name), "cpu")) { + if (s_contains(str_to_lower(name), "cpu") or s_contains(str_to_lower(name), "k10temp")) { cpu_sensor = name; break; } @@ -731,7 +763,7 @@ namespace Mem { ifstream meminfo(Shared::procPath / "meminfo"); if (meminfo.good()) { bool got_avail = false; - for (string label; meminfo >> label;) { + for (string label; meminfo.peek() != 'D' and meminfo >> label;) { if (label == "MemFree:") { meminfo >> mem.stats.at("free"); mem.stats.at("free") <<= 10; @@ -905,8 +937,8 @@ namespace Mem { //? Get disk/partition stats for (auto& [mountpoint, disk] : disks) { if (std::error_code ec; not fs::exists(mountpoint, ec)) continue; - struct statvfs vfs; - if (statvfs(mountpoint.c_str(), &vfs) < 0) { + struct statvfs64 vfs; + if (statvfs64(mountpoint.c_str(), &vfs) < 0) { Logger::warning("Failed to get disk/partition stats with statvfs() for: " + mountpoint); continue; } @@ -1066,7 +1098,7 @@ namespace Net { auto& bandwidth = net.at(iface).bandwidth.at(dir); uint64_t val = saved_stat.last; - try { val = max((uint64_t)stoul(readfile(sys_file, "0")), val); } + try { val = max((uint64_t)stoull(readfile(sys_file, "0")), val); } catch (const std::invalid_argument&) {} catch (const std::out_of_range&) {} @@ -1708,4 +1740,4 @@ namespace Tools { } throw std::runtime_error("Failed get uptime from from " + (string)Shared::procPath + "/uptime"); } -} \ No newline at end of file +} diff --git a/src/osx/btop_collect.cpp b/src/osx/btop_collect.cpp index f5c43d7..ae4411a 100644 --- a/src/osx/btop_collect.cpp +++ b/src/osx/btop_collect.cpp @@ -26,6 +26,7 @@ tab-size = 4 #include #include #include +#include #include #include #include @@ -67,6 +68,7 @@ namespace Cpu { cpu_info current_cpu; fs::path freq_path = "/sys/devices/system/cpu/cpufreq/policy0/scaling_cur_freq"; bool got_sensors = false, cpu_temp_only = false; + int core_offset = 0; //* Populate found_sensors map bool get_sensors(); @@ -106,7 +108,8 @@ namespace Shared { fs::path passwd_path; uint64_t totalMem; - long pageSize, clkTck, coreCount, physicalCoreCount, arg_max; + long pageSize, coreCount, clkTck, physicalCoreCount, arg_max; + double machTck; int totalMem_len; void init() { @@ -129,6 +132,14 @@ namespace Shared { Logger::warning("Could not get system page size. Defaulting to 4096, processes memory usage might be incorrect."); } + mach_timebase_info_data_t convf; + if (mach_timebase_info(&convf) == KERN_SUCCESS) { + machTck = convf.numer / convf.denom; + } else { + Logger::warning("Could not get mach clock tick conversion factor. Defaulting to 100, processes cpu usage might be incorrect."); + machTck = 100; + } + clkTck = sysconf(_SC_CLK_TCK); if (clkTck <= 0) { clkTck = 100; @@ -170,6 +181,7 @@ namespace Cpu { string cpuName; string cpuHz; bool has_battery = true; + bool macM1 = false; tuple current_bat; const array time_names = {"user", "nice", "system", "idle"}; @@ -219,30 +231,45 @@ namespace Cpu { name += n + ' '; } name.pop_back(); - for (const auto ® : {regex("Processor"), regex("CPU"), regex("\\(R\\)"), regex("\\(TM\\)"), regex("Intel"), - regex("AMD"), regex("Core"), regex("\\d?\\.?\\d+[mMgG][hH][zZ]")}) { - name = std::regex_replace(name, reg, ""); - } - name = trim(name); + for (const auto& replace : {"Processor", "CPU", "(R)", "(TM)", "Intel", "AMD", "Core"}) { + name = s_replace(name, replace, ""); + name = s_replace(name, " ", " "); + } + name = trim(name); } return name; } bool get_sensors() { + Logger::debug("get_sensors(): show_coretemp=" + std::to_string(Config::getB("show_coretemp")) + " check_temp=" + std::to_string(Config::getB("check_temp"))); got_sensors = false; if (Config::getB("show_coretemp") and Config::getB("check_temp")) { ThermalSensors sensors; - if (sensors.getSensors().size() > 0) { + if (sensors.getSensors() > 0) { + Logger::debug("M1 sensors found"); got_sensors = true; + cpu_temp_only = true; + macM1 = true; } else { // try SMC (intel) + Logger::debug("checking intel"); SMCConnection smcCon; try { long long t = smcCon.getTemp(-1); // check if we have package T if (t > -1) { + Logger::debug("intel sensors found"); got_sensors = true; + t = smcCon.getTemp(0); + if (t == -1) { + // for some macs the core offset is 1 - check if we get a sane value with 1 + if (smcCon.getTemp(1) > -1) { + Logger::debug("intel sensors with offset 1"); + core_offset = 1; + } + } } else { + Logger::debug("no intel sensors found"); got_sensors = false; } } catch (std::runtime_error &e) { @@ -257,41 +284,29 @@ namespace Cpu { void update_sensors() { current_cpu.temp_max = 95; // we have no idea how to get the critical temp try { - ThermalSensors sensors; - auto sensor = sensors.getSensors(); - if (sensor.size() > 0) { - current_cpu.temp.at(0).push_back((long long)sensor[0]); + if (macM1) { + ThermalSensors sensors; + current_cpu.temp.at(0).push_back(sensors.getSensors()); if (current_cpu.temp.at(0).size() > 20) current_cpu.temp.at(0).pop_front(); - if (Config::getB("show_coretemp") and not cpu_temp_only) { - for (int core = 1; core <= Shared::coreCount; core++) { - long long temp = (long long)sensor[core]; - if (cmp_less(core, current_cpu.temp.size())) { - current_cpu.temp.at(core).push_back(temp); - if (current_cpu.temp.at(core).size() > 20) - current_cpu.temp.at(core).pop_front(); - } - } - } } else { SMCConnection smcCon; int threadsPerCore = Shared::coreCount / Shared::physicalCoreCount; long long packageT = smcCon.getTemp(-1); // -1 returns package T current_cpu.temp.at(0).push_back(packageT); - if (Config::getB("show_coretemp") and not cpu_temp_only) { - for (int core = 0; core < Shared::coreCount; core++) { - long long temp = smcCon.getTemp(core / threadsPerCore); // same temp for all threads of same physical core - if (cmp_less(core + 1, current_cpu.temp.size())) { - current_cpu.temp.at(core + 1).push_back(temp); - if (current_cpu.temp.at(core + 1).size() > 20) - current_cpu.temp.at(core + 1).pop_front(); - } + for (int core = 0; core < Shared::coreCount; core++) { + long long temp = smcCon.getTemp((core / threadsPerCore) + core_offset); // same temp for all threads of same physical core + if (cmp_less(core + 1, current_cpu.temp.size())) { + current_cpu.temp.at(core + 1).push_back(temp); + if (current_cpu.temp.at(core + 1).size() > 20) + current_cpu.temp.at(core + 1).pop_front(); } } } } catch (std::runtime_error &e) { + got_sensors = false; Logger::error("failed getting CPU temp"); } } @@ -1116,7 +1131,7 @@ namespace Proc { //? Process runtime : current time - start time (both in unix time - seconds since epoch) struct timeval currentTime; gettimeofday(¤tTime, NULL); - detailed.elapsed = sec_to_dhms(currentTime.tv_sec - detailed.entry.cpu_s); // only interested in second granularity, so ignoring tc_usec + detailed.elapsed = sec_to_dhms(currentTime.tv_sec - (detailed.entry.cpu_s / 1'000'000)); if (detailed.elapsed.size() > 8) detailed.elapsed.resize(detailed.elapsed.size() - 3); //? Get parent process name @@ -1182,19 +1197,20 @@ namespace Proc { Logger::error("Failed getting CPU load info"); } cpu_load_info = (processor_cpu_load_info_data_t *)info.info_array; - cputimes = (cpu_load_info[0].cpu_ticks[CPU_STATE_USER] - + cpu_load_info[0].cpu_ticks[CPU_STATE_NICE] - + cpu_load_info[0].cpu_ticks[CPU_STATE_SYSTEM] - + cpu_load_info[0].cpu_ticks[CPU_STATE_IDLE]); + cputimes = 0; + for (natural_t i = 0; i < cpu_count; i++) { + cputimes += (cpu_load_info[i].cpu_ticks[CPU_STATE_USER] + + cpu_load_info[i].cpu_ticks[CPU_STATE_NICE] + + cpu_load_info[i].cpu_ticks[CPU_STATE_SYSTEM] + + cpu_load_info[i].cpu_ticks[CPU_STATE_IDLE]); + } } should_filter = true; int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0}; vector found; size_t size = 0; - struct timeval currentTime; - gettimeofday(¤tTime, NULL); - const double timeNow = currentTime.tv_sec + (currentTime.tv_usec / 1'000'000); + const auto timeNow = time_micros(); if (sysctl(mib, 4, NULL, &size, NULL, 0) < 0 || size == 0) { Logger::error("Unable to get size of kproc_infos"); @@ -1205,7 +1221,7 @@ namespace Proc { if (sysctl(mib, 4, processes.get(), &size, NULL, 0) == 0) { size_t count = size / sizeof(struct kinfo_proc); for (size_t i = 0; i < count; i++) { //* iterate over all processes in kinfo_proc - struct kinfo_proc kproc = processes.get()[i]; + struct kinfo_proc& kproc = processes.get()[i]; const size_t pid = (size_t)kproc.kp_proc.p_pid; if (pid < 1) continue; found.push_back(pid); @@ -1230,18 +1246,18 @@ namespace Proc { new_proc.name = f_name.substr(lastSlash + 1); //? Get process arguments if possible, fallback to process path in case of failure if (Shared::arg_max > 0) { - string proc_args; - proc_args.resize(Shared::arg_max); + std::unique_ptr proc_chars(new char[Shared::arg_max]); int mib[] = {CTL_KERN, KERN_PROCARGS2, (int)pid}; size_t argmax = Shared::arg_max; - if (sysctl(mib, 3, proc_args.data(), &argmax, NULL, 0) == 0) { - int argc; - memcpy(&argc, &proc_args[0], sizeof(argc)); + if (sysctl(mib, 3, proc_chars.get(), &argmax, NULL, 0) == 0) { + int argc = 0; + memcpy(&argc, &proc_chars.get()[0], sizeof(argc)); + std::string_view proc_args(proc_chars.get(), argmax); if (size_t null_pos = proc_args.find('\0', sizeof(argc)); null_pos != string::npos) { if (size_t start_pos = proc_args.find_first_not_of('\0', null_pos); start_pos != string::npos) { while (argc-- > 0 and null_pos != string::npos) { null_pos = proc_args.find('\0', start_pos); - new_proc.cmd += proc_args.substr(start_pos, null_pos - start_pos) + ' '; + new_proc.cmd += (string)proc_args.substr(start_pos, null_pos - start_pos) + ' '; start_pos = null_pos + 1; } } @@ -1251,7 +1267,7 @@ namespace Proc { } if (new_proc.cmd.empty()) new_proc.cmd = f_name; new_proc.ppid = kproc.kp_eproc.e_ppid; - new_proc.cpu_s = round(kproc.kp_proc.p_starttime.tv_sec + (kproc.kp_proc.p_starttime.tv_usec / 1'000'000)); + new_proc.cpu_s = kproc.kp_proc.p_starttime.tv_sec * 1'000'000 + kproc.kp_proc.p_starttime.tv_usec; struct passwd *pwd = getpwuid(kproc.kp_eproc.e_ucred.cr_uid); new_proc.user = pwd->pw_name; } @@ -1263,15 +1279,16 @@ namespace Proc { if (sizeof(pti) == proc_pidinfo(new_proc.pid, PROC_PIDTASKINFO, 0, &pti, sizeof(pti))) { new_proc.threads = pti.pti_threadnum; new_proc.mem = pti.pti_resident_size; - cpu_t = round((pti.pti_total_user + pti.pti_total_system) / 1'000); + cpu_t = pti.pti_total_user + pti.pti_total_system; + if (new_proc.cpu_t == 0) new_proc.cpu_t = cpu_t; } //? Process cpu usage since last update - new_proc.cpu_p = clamp(round(cmult * (cpu_t - new_proc.cpu_t) / max((uint64_t)1, cputimes - old_cputimes)) / 10.0, 0.0, 100.0 * Shared::coreCount); + new_proc.cpu_p = clamp(round(((cpu_t - new_proc.cpu_t) * Shared::machTck) / ((cputimes - old_cputimes) * Shared::clkTck)) * cmult / 1000.0, 0.0, 100.0 * Shared::coreCount); //? Process cumulative cpu usage since process start - new_proc.cpu_c = (double)(cpu_t * Shared::clkTck) / max(1.0, timeNow - new_proc.cpu_s); + new_proc.cpu_c = (double)(cpu_t * Shared::machTck) / (timeNow - new_proc.cpu_s); //? Update cached value with latest cpu times new_proc.cpu_t = cpu_t; diff --git a/src/osx/sensors.cpp b/src/osx/sensors.cpp index 851b284..56aca68 100644 --- a/src/osx/sensors.cpp +++ b/src/osx/sensors.cpp @@ -3,10 +3,9 @@ #include #include -#include -#include -#include #include +#include +#include extern "C" { typedef struct __IOHIDEvent *IOHIDEventRef; @@ -38,7 +37,8 @@ CFDictionaryRef matching(int page, int usage) { nums[1] = CFNumberCreate(0, kCFNumberSInt32Type, &usage); CFDictionaryRef dict = CFDictionaryCreate(0, (const void **)keys, (const void **)nums, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - CFRelease(keys); + CFRelease(keys[0]); + CFRelease(keys[1]); return dict; } @@ -54,14 +54,14 @@ double getValue(IOHIDServiceClientRef sc) { } // extern C -unordered_flat_map Cpu::ThermalSensors::getSensors() { - unordered_flat_map cpuValues; +long long Cpu::ThermalSensors::getSensors() { CFDictionaryRef thermalSensors = matching(0xff00, 5); // 65280_10 = FF00_16 // thermalSensors's PrimaryUsagePage should be 0xff00 for M1 chip, instead of 0xff05 // can be checked by ioreg -lfx IOHIDEventSystemClientRef system = IOHIDEventSystemClientCreate(kCFAllocatorDefault); IOHIDEventSystemClientSetMatching(system, thermalSensors); CFArrayRef matchingsrvs = IOHIDEventSystemClientCopyServices(system); + std::vector temps; if (matchingsrvs) { long count = CFArrayGetCount(matchingsrvs); for (int i = 0; i < count; i++) { @@ -72,19 +72,13 @@ unordered_flat_map Cpu::ThermalSensors::getSensors() { char buf[200]; CFStringGetCString(name, buf, 200, kCFStringEncodingASCII); std::string n(buf); - if (n.starts_with("PMU tdie")) { - // this is just a guess, nobody knows which sensors mean what - // on my system PMU tdie 3 and 9 are missing... - // there is also PMU tdev1-8 but it has negative values?? - // there is also eACC for efficiency package but it only has 2 entries - // and pACC for performance but it has 7 entries (2 - 9) WTF - std::string indexString = n.substr(8, 1); - int index = stoi(indexString); - cpuValues[index - 1] = getValue(sc); - Logger::debug("T " + n + "=" + std::to_string(cpuValues[index - 1])); - } else if (n == "SOC MTR Temp Sensor0") { - // package T for Apple Silicon - also a guess - cpuValues[0] = getValue(sc); + // this is just a guess, nobody knows which sensors mean what + // on my system PMU tdie 3 and 9 are missing... + // there is also PMU tdev1-8 but it has negative values?? + // there is also eACC for efficiency package but it only has 2 entries + // and pACC for performance but it has 7 entries (2 - 9) WTF + if (n.starts_with("eACC") or n.starts_with("pACC")) { + temps.push_back(getValue(sc)); } CFRelease(name); } @@ -94,5 +88,6 @@ unordered_flat_map Cpu::ThermalSensors::getSensors() { } CFRelease(system); CFRelease(thermalSensors); - return cpuValues; + if (temps.empty()) return 0ll; + return round(std::accumulate(temps.begin(), temps.end(), 0ll) / temps.size()); } diff --git a/src/osx/sensors.hpp b/src/osx/sensors.hpp index 1056437..48287ee 100644 --- a/src/osx/sensors.hpp +++ b/src/osx/sensors.hpp @@ -1,10 +1,7 @@ -#include - -using robin_hood::unordered_flat_map; namespace Cpu { class ThermalSensors { public: - unordered_flat_map getSensors(); + long long getSensors(); }; } // namespace Cpu diff --git a/src/osx/smc.cpp b/src/osx/smc.cpp index 2482ae3..54fa422 100644 --- a/src/osx/smc.cpp +++ b/src/osx/smc.cpp @@ -50,27 +50,39 @@ namespace Cpu { IOServiceClose(conn); } + long long SMCConnection::getSMCTemp(char *key) { + SMCVal_t val; + kern_return_t result; + result = SMCReadKey(key, &val); + if (result == kIOReturnSuccess) { + if (val.dataSize > 0) { + if (strcmp(val.dataType, DATATYPE_SP78) == 0) { + // convert sp78 value to temperature + int intValue = val.bytes[0] * 256 + (unsigned char)val.bytes[1]; + return static_cast(intValue / 256.0); + } + } + } + return -1; + } + // core means physical core in SMC, while in core map it's cpu threads :-/ Only an issue on hackintosh? // this means we can only get the T per physical core // another issue with the SMC API is that the key is always 4 chars -> what with systems with more than 9 physical cores? // no Mac models with more than 18 threads are released, so no problem so far // according to VirtualSMC docs (hackintosh fake SMC) the enumeration follows with alphabetic chars - not implemented yet here (nor in VirtualSMC) long long SMCConnection::getTemp(int core) { - SMCVal_t val; - kern_return_t result; char key[] = SMC_KEY_CPU_TEMP; if (core >= 0) { snprintf(key, 5, "TC%1dc", core); } - result = SMCReadKey(key, &val); - if (result == kIOReturnSuccess) { - if (strcmp(val.dataType, DATATYPE_SP78) == 0) { - // convert sp78 value to temperature - int intValue = val.bytes[0] * 256 + (unsigned char)val.bytes[1]; - return static_cast(intValue / 256.0); - } + long long result = getSMCTemp(key); + if (result == -1) { + // try again with C + snprintf(key, 5, "TC%1dC", core); + result = getSMCTemp(key); } - return -1; + return result; } kern_return_t SMCConnection::SMCReadKey(UInt32Char_t key, SMCVal_t *val) { diff --git a/src/osx/smc.hpp b/src/osx/smc.hpp index 0aa02c1..87ed2ef 100644 --- a/src/osx/smc.hpp +++ b/src/osx/smc.hpp @@ -25,7 +25,9 @@ #define DATATYPE_SP78 "sp78" // key values -#define SMC_KEY_CPU_TEMP "TC0P" +#define SMC_KEY_CPU_TEMP "TC0P" // proximity temp? +#define SMC_KEY_CPU_DIODE_TEMP "TC0D" // diode temp? +#define SMC_KEY_CPU_DIE_TEMP "TC0F" // die temp? #define SMC_KEY_CPU1_TEMP "TC1C" #define SMC_KEY_CPU2_TEMP "TC2C" // etc #define SMC_KEY_FAN0_RPM_CUR "F0Ac" @@ -85,6 +87,7 @@ namespace Cpu { private: kern_return_t SMCReadKey(UInt32Char_t key, SMCVal_t *val); + long long getSMCTemp(char *key); kern_return_t SMCCall(int index, SMCKeyData_t *inputStructure, SMCKeyData_t *outputStructure); io_connect_t conn; diff --git a/themes/ayu.theme b/themes/ayu.theme new file mode 100644 index 0000000..58d89b4 --- /dev/null +++ b/themes/ayu.theme @@ -0,0 +1,89 @@ +# Main background, empty for terminal default, need to be empty if you want transparent background +theme[main_bg]="#0B0E14" + +# Main text color +theme[main_fg]="#BFBDB6" + +# Title color for boxes +theme[title]="#BFBDB6" + +# Highlight color for keyboard shortcuts +theme[hi_fg]="#E6B450" + +# Background color of selected item in processes box +theme[selected_bg]="#E6B450" + +# Foreground color of selected item in processes box +theme[selected_fg]="#f8f8f2" + +# Color of inactive/disabled text +theme[inactive_fg]="#565B66" + +# Color of text appearing on top of graphs, i.e uptime and current network graph scaling +theme[graph_text]="#BFBDB6" + +# Background color of the percentage meters +theme[meter_bg]="#565B66" + +# Misc colors for processes box including mini cpu graphs, details memory graph and details status text +theme[proc_misc]="#DFBFFF" + +# Cpu box outline color +theme[cpu_box]="#DFBFFF" + +# Memory/disks box outline color +theme[mem_box]="#95E6CB" + +# Net up/down box outline color +theme[net_box]="#F28779" + +# Processes box outline color +theme[proc_box]="#E6B673" + +# Box divider line and small boxes line color +theme[div_line]="#565B66" + +# Temperature graph colors +theme[temp_start]="#DFBFFF" +theme[temp_mid]="#D2A6FF" +theme[temp_end]="#A37ACC" + +# CPU graph colors +theme[cpu_start]="#DFBFFF" +theme[cpu_mid]="#D2A6FF" +theme[cpu_end]="#A37ACC" + +# Mem/Disk free meter +theme[free_start]="#95E6CB" +theme[free_mid]="#95E6CB" +theme[free_end]="#4CBF99" + +# Mem/Disk cached meter +theme[cached_start]="#95E6CB" +theme[cached_mid]="#95E6CB" +theme[cached_end]="#4CBF99" + +# Mem/Disk available meter +theme[available_start]="#95E6CB" +theme[available_mid]="#95E6CB" +theme[available_end]="#4CBF99" + +# Mem/Disk used meter +theme[used_start]="#95E6CB" +theme[used_mid]="#95E6CB" +theme[used_end]="#4CBF99" + +# Download graph colors +theme[download_start]="#F28779" +theme[download_mid]="#F07178" +theme[download_end]="#F07171" + +# Upload graph colors +theme[upload_start]="#73D0FF" +theme[upload_mid]="#59C2FF" +theme[upload_end]="#399EE6" + +# Process box color gradient for threads, mem and cpu usage +theme[process_start]="#FFCC66" +theme[process_mid]="#E6B450" +theme[process_end]="#FFAA33" diff --git a/themes/gruvbox_dark_v2.theme b/themes/gruvbox_dark_v2.theme new file mode 100644 index 0000000..a3a0c9e --- /dev/null +++ b/themes/gruvbox_dark_v2.theme @@ -0,0 +1,98 @@ +# Bashtop gruvbox (https://github.com/morhetz/gruvbox) theme +# First version created By BachoSeven +# Adjustments to proper colors by Pietryszak (https://github.com/pietryszak/) + +# Colors should be in 6 or 2 character hexadecimal or single spaced rgb decimal: "#RRGGBB", "#BW" or "0-255 0-255 0-255" +# example for white: "#FFFFFF", "#ff" or "255 255 255". + +# All graphs and meters can be gradients +# For single color graphs leave "mid" and "end" variable empty. +# Use "start" and "end" variables for two color gradient +# Use "start", "mid" and "end" for three color gradient + +# Main background, empty for terminal default, need to be empty if you want transparent background +theme[main_bg]="#282828" + +# Main text color +theme[main_fg]="#EBDBB2" + +# Title color for boxes +theme[title]="#EBDBB2" + +# Highlight color for keyboard shortcuts +theme[hi_fg]="#CC241D" + +# Background color of selected items +theme[selected_bg]="#32302F" + +# Foreground color of selected items +theme[selected_fg]="#D3869B" + +# Color of inactive/disabled text +theme[inactive_fg]="#3C3836" + +# Color of text appearing on top of graphs, i.e uptime and current network graph scaling +theme[graph_text]="#A89984" + +# Misc colors for processes box including mini cpu graphs, details memory graph and details status text +theme[proc_misc]="#98971A" + +# Cpu box outline color +theme[cpu_box]="#A89984" + +# Memory/disks box outline color +theme[mem_box]="#A89984" + +# Net up/down box outline color +theme[net_box]="#A89984" + +# Processes box outline color +theme[proc_box]="#A89984" + +# Box divider line and small boxes line color +theme[div_line]="#A89984" + +# Temperature graph colors +theme[temp_start]="#98971A" +theme[temp_mid]="" +theme[temp_end]="#CC241D" + +# CPU graph colors +theme[cpu_start]="#8EC07C" +theme[cpu_mid]="#D79921" +theme[cpu_end]="#CC241D" + +# Mem/Disk free meter +theme[free_start]="#CC241D" +theme[free_mid]="#D79921" +theme[free_end]="#8EC07C" + +# Mem/Disk cached meter +theme[cached_start]="#458588" +theme[cached_mid]="#83A598" +theme[cached_end]="#8EC07C" + +# Mem/Disk available meter +theme[available_start]="#CC241D" +theme[available_mid]="#D65D0E" +theme[available_end]="#FABD2F" + +# Mem/Disk used meter +theme[used_start]="#8EC07C" +theme[used_mid]="#D65D0E" +theme[used_end]="#CC241D" + +# Download graph colors +theme[download_start]="#98971A" +theme[download_mid]="#689d6A" +theme[download_end]="#B8BB26" + +# Upload graph colors +theme[upload_start]="#CC241D" +theme[upload_mid]="#D65d0E" +theme[upload_end]="#FABF2F" + +# Process box color gradient for threads, mem and cpu usage +theme[process_start]="#8EC07C" +theme[process_mid]="#FE8019" +theme[process_end]="#CC241D" diff --git a/themes/onedark.theme b/themes/onedark.theme new file mode 100644 index 0000000..f4441de --- /dev/null +++ b/themes/onedark.theme @@ -0,0 +1,81 @@ +# Theme: OneDark +# By: Vitor Melo + +# Main bg +theme[main_bg]="#282c34" + +# Main text color +theme[main_fg]="#abb2bf" + +# Title color for boxes +theme[title]="#abb2bf" + +# Higlight color for keyboard shortcuts +theme[hi_fg]="#61afef" + +# Background color of selected item in processes box +theme[selected_bg]="#2c313c" + +# Foreground color of selected item in processes box +theme[selected_fg]="#abb2bf" + +# Color of inactive/disabled text +theme[inactive_fg]="#5c6370" + +# Misc colors for processes box including mini cpu graphs, details memory graph and details status text +theme[proc_misc]="#61afef" + +# Cpu box outline color +theme[cpu_box]="#5c6370" + +# Memory/disks box outline color +theme[mem_box]="#5c6370" + +# Net up/down box outline color +theme[net_box]="#5c6370" + +# Processes box outline color +theme[proc_box]="#5c6370" + +# Box divider line and small boxes line color +theme[div_line]="#5c6370" + +# Temperature graph colors +theme[temp_start]="#98c379" +theme[temp_mid]="#e5c07b" +theme[temp_end]="#e06c75" + +# CPU graph colors +theme[cpu_start]="#98c379" +theme[cpu_mid]="#e5c07b" +theme[cpu_end]="#e06c75" + +# Mem/Disk free meter +theme[free_start]="#98c379" +theme[free_mid]="#e5c07b" +theme[free_end]="#e06c75" + +# Mem/Disk cached meter +theme[cached_start]="#98c379" +theme[cached_mid]="#e5c07b" +theme[cached_end]="#e06c75" + +# Mem/Disk available meter +theme[available_start]="#98c379" +theme[available_mid]="#e5c07b" +theme[available_end]="#e06c75" + +# Mem/Disk used meter +theme[used_start]="#98c379" +theme[used_mid]="#e5c07b" +theme[used_end]="#e06c75" + +# Download graph colors +theme[download_start]="#98c379" +theme[download_mid]="#e5c07b" +theme[download_end]="#e06c75" + +# Upload graph colors +theme[upload_start]="#98c379" +theme[upload_mid]="#e5c07b" +theme[upload_end]="#e06c75"