diff options
-rw-r--r-- | .github/ISSUE_TEMPLATE/bug_report.md | 6 | ||||
-rw-r--r-- | .github/workflows/continuous-build-linux.yml | 17 | ||||
-rw-r--r-- | .github/workflows/continuous-build-macos.yml | 13 | ||||
-rw-r--r-- | CHANGELOG.md | 84 | ||||
-rw-r--r-- | Makefile | 25 | ||||
-rw-r--r-- | README.md | 161 | ||||
-rw-r--r-- | src/btop.cpp | 167 | ||||
-rw-r--r-- | src/btop_config.cpp | 7 | ||||
-rw-r--r-- | src/btop_draw.cpp | 4 | ||||
-rw-r--r-- | src/btop_input.cpp | 21 | ||||
-rw-r--r-- | src/btop_menu.cpp | 17 | ||||
-rw-r--r-- | src/btop_shared.hpp | 4 | ||||
-rw-r--r-- | src/btop_tools.cpp | 38 | ||||
-rw-r--r-- | src/btop_tools.hpp | 21 | ||||
-rw-r--r-- | src/linux/btop_collect.cpp | 74 | ||||
-rw-r--r-- | src/osx/btop_collect.cpp | 113 | ||||
-rw-r--r-- | src/osx/sensors.cpp | 35 | ||||
-rw-r--r-- | src/osx/sensors.hpp | 5 | ||||
-rw-r--r-- | src/osx/smc.cpp | 32 | ||||
-rw-r--r-- | src/osx/smc.hpp | 5 | ||||
-rw-r--r-- | themes/ayu.theme | 89 | ||||
-rw-r--r-- | themes/gruvbox_dark_v2.theme | 98 | ||||
-rw-r--r-- | themes/onedark.theme | 81 |
23 files changed, 879 insertions, 238 deletions
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 @@ -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 @@ -5,6 +5,8 @@ </a> ![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! + +<details> +<summary>More...</summary> + +##### 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. +</details> + ## 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)-(ARCH)-(PLATFORM).tbz from [latest release](https://github.com/aristocratos/btop/releases/latest) and unpack to a new folder** -1. **Download btop-(VERSION)-(PLATFORM)-(ARCH).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=<architecture>` 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 <tuple> #include <regex> #include <chrono> +#ifdef __APPLE__ + #include <CoreFoundation/CoreFoundation.h> +#endif #include <btop_shared.hpp> #include <btop_tools.hpp> @@ -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<bool> resized (false); atomic<bool> quitting (false); + atomic<bool> should_quit (false); + atomic<bool> should_sleep (false); atomic<bool> _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,84 +444,83 @@ 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()); + throw std::runtime_error("Cpu:: -> " + (string)e.what()); } } - - //? NET - if (v_contains(conf.boxes, "net")) { + //? MEM + if (v_contains(conf.boxes, "mem")) { try { - if (Global::debug) debug_timer("net", collect_begin); + if (Global::debug) debug_timer("mem", collect_begin); //? Start collect - auto net = Net::collect(conf.no_update); + auto mem = Mem::collect(conf.no_update); - if (Global::debug) debug_timer("net", draw_begin); + if (Global::debug) debug_timer("mem", draw_begin); //? Draw box - if (not pause_output) output += Net::draw(net, conf.force_redraw, conf.no_update); + if (not pause_output) output += Mem::draw(mem, conf.force_redraw, conf.no_update); - if (Global::debug) debug_timer("net", draw_done); + if (Global::debug) debug_timer("mem", draw_done); } catch (const std::exception& e) { - throw std::runtime_error("Net:: -> " + (string)e.what()); + throw std::runtime_error("Mem:: -> " + (string)e.what()); } } - //? MEM - if (v_contains(conf.boxes, "mem")) { + //? NET + if (v_contains(conf.boxes, "net")) { try { - if (Global::debug) debug_timer("mem", collect_begin); + if (Global::debug) debug_timer("net", collect_begin); //? Start collect - auto mem = Mem::collect(conf.no_update); + auto net = Net::collect(conf.no_update); - if (Global::debug) debug_timer("mem", draw_begin); + if (Global::debug) debug_timer("net", draw_begin); //? Draw box - if (not pause_output) output += Mem::draw(mem, 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("mem", draw_done); + if (Global::debug) debug_timer("net", draw_done); } catch (const std::exception& e) { - throw std::runtime_error("Mem:: -> " + (string)e.what()); + throw std::runtime_error("Net:: -> " + (string)e.what()); } } - //? CPU - if (v_contains(conf.boxes, "cpu")) { + //? PROC + if (v_contains(conf.boxes, "proc")) { try { - if (Global::debug) debug_timer("cpu", collect_begin); + if (Global::debug) debug_timer("proc", collect_begin); //? Start collect - auto cpu = Cpu::collect(conf.no_update); + auto proc = Proc::collect(conf.no_update); - if (Global::debug) debug_timer("cpu", draw_begin); + if (Global::debug) debug_timer("proc", draw_begin); //? Draw box - if (not pause_output) output += Cpu::draw(cpu, conf.force_redraw, conf.no_update); + if (not pause_output) output += Proc::draw(proc, conf.force_redraw, conf.no_update); - if (Global::debug) debug_timer("cpu", draw_done); + if (Global::debug) debug_timer("proc", draw_done); } catch (const std::exception& e) { - throw std::runtime_error("Cpu:: -> " + (string)e.what()); + 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."); |