btop/src/btop.cpp
Jos Dehaes 3d7bb52e48 Squashed commit of the following:
commit 7add05599de74d8047a9802fd673ae62a91a3372
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Tue Jan 11 23:48:16 2022 +0100

    bring in line with upstream

commit ddb2fb0fac
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Tue Jan 11 23:35:21 2022 +0100

    fix CPU name

commit 01a1dda734
Merge: 3b6dac6 96ac114
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Tue Jan 11 23:29:17 2022 +0100

    merge main into freebsd

commit 3b6dac640e
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Tue Jan 11 23:17:07 2022 +0100

    disk IO working

commit 30b33730b3
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Tue Jan 11 22:47:44 2022 +0100

    reduce memleak drastically

commit 682746ff0e
Merge: 9fdf6d0 891051c
Author: Jakob P. Liljenberg <admin@qvantnet.com>
Date:   Sat Dec 18 19:50:13 2021 +0100

    Merge pull request #186 from GuillaumeGomez/freebsd

    Remove duplicated fstype

commit 891051c8ab
Author: Guillaume Gomez <guillaume1.gomez@gmail.com>
Date:   Sun Dec 5 23:03:17 2021 +0100

    Remove duplicated fstype

commit 9fdf6d0204
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Sat Nov 27 20:55:49 2021 +0100

    iterate over ALL pools

commit 860a9fe472
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Sat Nov 27 20:30:43 2021 +0100

    RAII

commit 7c433be4a6
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Sun Nov 21 21:36:44 2021 +0100

    regular filesystems + ZFS

commit 70d9777908
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Sat Nov 20 22:57:00 2021 +0100

    some comment + minor cleanup

commit a61df3ff98
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Sat Nov 20 22:51:49 2021 +0100

    it does some IO!!

commit f32358bd47
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Tue Nov 16 22:30:55 2021 +0100

    correct unit number

commit d12b4d9d23
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Tue Nov 16 21:58:12 2021 +0100

    readability

commit a6602ff22b
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Tue Nov 16 21:53:33 2021 +0100

    correctly iterate over devstat. still no idea how to map the devices we get back here to mountpoints

commit e64610a163
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Tue Nov 16 21:20:42 2021 +0100

    RAII

commit 98693aac25
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Sun Oct 24 21:04:04 2021 +0200

    devstat WIP

commit 8940d68f47
Author: aristocratos <gnmjpl@gmail.com>
Date:   Sun Oct 24 16:15:29 2021 +0200

    Fixed cpu usage in cpu box, process cpu usage still wrong

commit b547ccb258
Author: aristocratos <gnmjpl@gmail.com>
Date:   Sun Oct 24 11:25:28 2021 +0200

    Makefile even with OSX Makefile

commit a5eabe20b6
Author: aristocratos <gnmjpl@gmail.com>
Date:   Sun Oct 24 11:20:46 2021 +0200

    Updated Makefile

commit 18451ceb05
Author: aristocratos <gnmjpl@gmail.com>
Date:   Sun Oct 24 11:13:15 2021 +0200

    Updated Makefile

commit ca183b2b85
Author: aristocratos <gnmjpl@gmail.com>
Date:   Sun Oct 24 11:09:29 2021 +0200

    Fixed up Makefile

commit 235c95274f
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Sat Oct 23 23:49:51 2021 +0200

    fix boottime (not sure if needed)

commit cc2a4987ef
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Sat Oct 23 23:38:00 2021 +0200

    temp

commit 30ef6ee050
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Sat Oct 23 22:58:17 2021 +0200

    cpu freq

commit 735894b6ca
Author: aristocratos <gnmjpl@gmail.com>
Date:   Sat Oct 23 21:46:57 2021 +0200

    Fixed leaks and proc tree mode

commit cd3fd1a529
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Fri Oct 22 22:27:32 2021 +0200

    correct makefile

commit cd644cfc55
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Fri Oct 22 15:49:39 2021 +0200

    get rid of warnings

commit 81b63652bf
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Fri Oct 22 15:43:22 2021 +0200

    battery

commit 41ba986954
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Fri Oct 22 15:31:04 2021 +0200

    process args

commit 137e876da6
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Fri Oct 22 14:29:36 2021 +0200

    remove debug

commit 5249be0a40
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Fri Oct 22 14:28:40 2021 +0200

    net stats

commit 96461f4d94
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Fri Oct 22 13:54:00 2021 +0200

    sane memory stats

commit e5ceeee197
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Fri Oct 22 13:38:27 2021 +0200

    processes

commit 889433d4c6
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Fri Oct 22 12:08:47 2021 +0200

    cpu model  + cpu load

commit f037ab306a
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Fri Oct 22 10:31:37 2021 +0200

    freebsd first work

commit de62167921
Merge: a590dd3 a0ee404
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Wed Oct 20 23:10:36 2021 +0200

    Merge branch 'main' into OSX

    # Conflicts:
    #	CHANGELOG.md
    #	Makefile
    #	src/btop.cpp

commit a590dd3f67
Author: aristocratos <admin@qvantnet.com>
Date:   Mon Oct 18 11:20:12 2021 +0200

    Ignore format-truncation

commit 4c30742d41
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Mon Oct 18 10:08:01 2021 +0200

    comments about temp sensors

commit 46030de77c
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Mon Oct 18 08:10:37 2021 +0200

    available = total - used

commit 4c228de0ef
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Sun Oct 17 22:19:41 2021 +0200

    use sysconf to get arg_max - seems simpler

commit c60fc29f0f
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Sun Oct 17 22:10:50 2021 +0200

    arg_max should be int on macos

commit 0b5a931a6d
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Sun Oct 17 22:01:42 2021 +0200

    only fetch max_args once

commit 71d5cd5fd9
Author: aristocratos <admin@qvantnet.com>
Date:   Sat Oct 16 23:24:07 2021 +0200

    Reverted mutexes back to custom atomic bool based locks

commit 3f34a67df6
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Sat Oct 16 21:47:55 2021 +0200

    these helpers can be static

commit fc19c46c8a
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Sat Oct 16 21:44:49 2021 +0200

    code cleanup: put the code in .cpp to enable incremental build

commit c252c618c0
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Sat Oct 16 21:09:21 2021 +0200

    don't crash on intel

commit 9f88187c29
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Sat Oct 16 21:06:18 2021 +0200

    small improvement

commit 808f09c974
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Sat Oct 16 20:59:48 2021 +0200

    don't iterate 3 times

commit d8408336e3
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Sat Oct 16 20:59:27 2021 +0200

    remove debug

commit 4f078c3beb
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Wed Oct 13 23:38:27 2021 +0200

    more temperature (M1 + intel)

commit 289880aaa6
Merge: 88a2528 3ffb212
Author: aristocratos <admin@qvantnet.com>
Date:   Sat Oct 16 19:37:09 2021 +0200

    Merge branch 'OSX' of github.com:aristocratos/btop into OSX

commit 88a2528ca3
Author: aristocratos <admin@qvantnet.com>
Date:   Sat Oct 16 19:34:10 2021 +0200

    Merge changes from main

commit 3ffb21203a
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Sat Oct 16 19:20:45 2021 +0200

    release a bit more - still has negative temps for 2 cores on my system

commit 70b4871062
Author: aristocratos <admin@qvantnet.com>
Date:   Sat Oct 16 01:59:44 2021 +0200

    Fixed leaks in Mem and attempt at fixing leaks in sensors.cpp

commit fbae907720
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Fri Oct 15 23:41:37 2021 +0200

    temperature sensors via IOKit

commit cef0f0a68d
Author: aristocratos <admin@qvantnet.com>
Date:   Fri Oct 15 18:39:17 2021 +0200

    Process command line arguments

commit 921cfa01ff
Author: aristocratos <admin@qvantnet.com>
Date:   Wed Oct 13 23:20:15 2021 +0200

    Re-enable setuid and set default SU_GROUP to wheel for OSX

commit a416c888c7
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Wed Oct 13 21:16:41 2021 +0200

    temperature

commit e7afe00ce7
Author: aristocratos <admin@qvantnet.com>
Date:   Wed Oct 13 12:54:43 2021 +0200

    Cpu usage working again

commit 4193ef8921
Author: aristocratos <admin@qvantnet.com>
Date:   Wed Oct 13 10:36:51 2021 +0200

    Fixed cpu lazy sorting

commit 93fcb6ff04
Author: aristocratos <admin@qvantnet.com>
Date:   Tue Oct 12 22:22:45 2021 +0200

    Update README.md

commit 683354cd2e
Merge: 8a399c4 6d724d6
Author: aristocratos <admin@qvantnet.com>
Date:   Tue Oct 12 22:19:30 2021 +0200

    Merge pull request #80 from ShrirajHegde/OSX

    Add github workflow for MacOS

commit 8a399c499a
Author: aristocratos <admin@qvantnet.com>
Date:   Tue Oct 12 21:50:46 2021 +0200

    pointer to smart pointer, first pass

commit 772605003a
Author: aristocratos <admin@qvantnet.com>
Date:   Tue Oct 12 18:54:38 2021 +0200

    Fixed detailed memory not updating

commit 28cb677533
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Mon Oct 11 22:19:25 2021 +0200

    more memory free-up - still leaks like crazy

commit 304457863f
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Mon Oct 11 21:48:07 2021 +0200

    more RAII cleanup

commit 82e2e3c55c
Author: aristocratos <admin@qvantnet.com>
Date:   Mon Oct 11 12:40:25 2021 +0200

    Removed non present cpu fields and fixed calculation for selectable cpu field graphs

commit 68603f2b37
Author: aristocratos <admin@qvantnet.com>
Date:   Mon Oct 11 10:57:04 2021 +0200

    RAII Wrappers for Cpu::get_battery()

commit d5cb24fbeb
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Sun Oct 10 20:23:11 2021 +0200

    RAII

commit 8fad5a61be
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Sat Oct 9 21:44:16 2021 +0200

    get more disk IO stats

commit 7fa903cf16
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Sat Oct 9 21:43:48 2021 +0200

    fix build

commit 98036db660
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Sat Oct 9 21:18:25 2021 +0200

    remove unnecessary uptime param

commit aae7ae35ca
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Sat Oct 9 21:07:23 2021 +0200

    remove debug logging

commit 5187420b04
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Sat Oct 9 21:06:43 2021 +0200

    fix process elapsed time

commit 89582c0ea6
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Sat Oct 9 21:06:29 2021 +0200

    don't double free

commit 6d724d6155
Author: Shriraj Hegde <shriraj.hegde@gmail.com>
Date:   Sat Oct 9 21:46:33 2021 +0530

    Change Upload filename

commit 4f94ecc8ad
Author: Shriraj Hegde <shriraj.hegde@gmail.com>
Date:   Sat Oct 9 21:40:11 2021 +0530

    Fix upload path

commit e1d6d0a1f2
Author: Shriraj Hegde <shriraj.hegde@gmail.com>
Date:   Sat Oct 9 21:36:13 2021 +0530

    Skip installing gcc via Homebrew
    Change job name

commit 02cdd9d759
Author: Shriraj Hegde <shriraj.hegde@gmail.com>
Date:   Sat Oct 9 21:30:40 2021 +0530

    Fix uploading
    Remove distclean

commit 39eb6c396f
Author: Shriraj Hegde <shriraj.hegde@gmail.com>
Date:   Sat Oct 9 21:26:57 2021 +0530

    Disable static compilation

commit 099592bccd
Author: aristocratos <admin@qvantnet.com>
Date:   Sat Oct 9 17:52:10 2021 +0200

    Ignore empty pid 0 to fix tree mode

commit a28e17556e
Author: Shriraj Hegde <shriraj.hegde@gmail.com>
Date:   Sat Oct 9 21:17:11 2021 +0530

    Add workflow for MacOS

commit aee9179c0a
Author: aristocratos <admin@qvantnet.com>
Date:   Sat Oct 9 17:36:46 2021 +0200

    Disable failed tty mode detection for OSX

commit 4b7b98058d
Author: aristocratos <admin@qvantnet.com>
Date:   Sat Oct 9 11:28:32 2021 +0200

    Fixed disk io and added io activity based on read/write

commit bfa0629e7d
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Fri Oct 8 22:28:10 2021 +0200

    fill in 0 for ioticks

commit a016ff8a03
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Fri Oct 8 22:16:01 2021 +0200

    disk io from IOreg. Does not show any io though

commit f98606c6db
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Fri Oct 8 09:32:06 2021 +0200

    per process IO stats

commit c8b50ed488
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Fri Oct 8 00:11:08 2021 +0200

    don't show autofs, it's useless

commit c4df64d440
Author: aristocratos <admin@qvantnet.com>
Date:   Thu Oct 7 18:41:49 2021 +0200

    Fixed compile time display for gmake and command timings

commit b3e6f495f7
Author: aristocratos <admin@qvantnet.com>
Date:   Thu Oct 7 18:26:15 2021 +0200

    Fixed clk_tck -> clkTck

commit e53799188f
Author: aristocratos <admin@qvantnet.com>
Date:   Thu Oct 7 18:25:14 2021 +0200

    Fixed better detection for OSX

commit b864edf984
Author: aristocratos <admin@qvantnet.com>
Date:   Thu Oct 7 18:24:37 2021 +0200

    Fixed cumulative cpu usage

commit 6a3c5d9b97
Author: aristocratos <admin@qvantnet.com>
Date:   Thu Oct 7 13:20:30 2021 +0200

    Proc::collect() better cpu percent accurazy

commit 84d0596294
Merge: 3564f8e 98e1e87
Author: aristocratos <admin@qvantnet.com>
Date:   Thu Oct 7 12:56:55 2021 +0200

    Merge branch 'OSX' of github.com:aristocratos/btop into OSX

commit 3564f8e4c2
Author: aristocratos <admin@qvantnet.com>
Date:   Thu Oct 7 12:56:27 2021 +0200

    Proc::collect() fixed cputimes and cpu percentage calc

commit 98e1e87405
Merge: 60c5636 d96fdd7
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Thu Oct 7 11:32:41 2021 +0200

    Merge branch 'main' into OSX

commit 60c5636cd7
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Wed Oct 6 22:45:54 2021 +0200

    fix warning

commit 489e446152
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Wed Oct 6 22:38:40 2021 +0200

    details + process states

commit 7e5a808c73
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Wed Oct 6 22:38:19 2021 +0200

    avoid details crash

commit 9c9da4606b
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Wed Oct 6 21:03:21 2021 +0200

    fix quit on macos

commit ec7415384d
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Wed Oct 6 00:41:37 2021 +0200

    fix mistake in makefile

commit 5ac8fa4c8a
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Wed Oct 6 18:56:13 2021 +0200

    don't show /dev

commit d901bbebd9
Author: aristocratos <gnmjpl@gmail.com>
Date:   Wed Oct 6 17:27:51 2021 +0200

     Ignore tags and other branches

commit c7f1e71e29
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Wed Oct 6 16:00:41 2021 +0200

    comment

commit b9d58e3faf
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Wed Oct 6 15:55:58 2021 +0200

    impossible to get CPU freq on M1 apparently

commit 66072711c2
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Wed Oct 6 15:33:43 2021 +0200

    detect full

commit 6bb0e930a2
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Wed Oct 6 00:38:46 2021 +0200

    CPU freq in GHz

commit a5f10f1a0f
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Wed Oct 6 15:13:18 2021 +0200

    check array length

commit 155c848b97
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Wed Oct 6 15:05:20 2021 +0200

    switch to other way to get CPU freq (still does not work)

commit cf51ba2ebe
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Wed Oct 6 14:45:44 2021 +0200

    remove some warnings

commit 775dff5f72
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Wed Oct 6 14:16:45 2021 +0200

    fix link

commit 8c67967775
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Wed Oct 6 14:16:38 2021 +0200

    reduce diff more

commit 70b47d2ca8
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Wed Oct 6 14:10:23 2021 +0200

    reduce diff with main branch

commit ca9cb48054
Merge: d0c6c0a c66b46f
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Wed Oct 6 13:49:20 2021 +0200

    Merge remote-tracking branch 'origin/main' into OSX

    # Conflicts:
    #	Makefile
    #	src/osx/btop_collect.cpp

commit c66b46f850
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Wed Oct 6 13:41:57 2021 +0200

    battery state via CoreFoundation

commit d0c6c0a362
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Wed Oct 6 10:51:36 2021 +0200

    all disks + load averages

commit ca67526dc1
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Wed Oct 6 10:33:55 2021 +0200

    show all disks

commit 56119f99a9
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Wed Oct 6 00:17:41 2021 +0200

    procs sorting/filtering

commit 8d86011d72
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Tue Oct 5 23:42:17 2021 +0200

    battery states

commit a9b64d62e4
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Tue Oct 5 23:24:59 2021 +0200

    battery hack works on M1

commit ce51031142
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Tue Oct 5 23:18:22 2021 +0200

    ugly hack to get battery

commit d5e6725c6c
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Tue Oct 5 22:42:42 2021 +0200

    CPU stuff

commit 5c02bd8c83
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Tue Oct 5 21:25:42 2021 +0200

    network

commit d5da9d4983
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Tue Oct 5 15:43:05 2021 +0200

    correct cached size

commit 5f11aba504
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Tue Oct 5 12:03:48 2021 +0200

    vm stats from syscall + swap

commit 776fc96852
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Tue Oct 5 10:48:07 2021 +0200

    seems to work indeed

commit 7b40e2835a
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Tue Oct 5 10:46:14 2021 +0200

    allow override optimization flag

commit 005ea24e4c
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Tue Oct 5 10:09:24 2021 +0200

    update Makefile

commit af8cec9deb
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Mon Oct 4 15:32:55 2021 +0200

    some more params

commit 7ebe4f7594
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Mon Oct 4 15:15:55 2021 +0200

    show more disks

commit e50a56394a
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Mon Oct 4 14:52:56 2021 +0200

    disks show something

commit 6497a8c202
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Mon Oct 4 09:15:35 2021 +0200

    reformat

commit 28e152b80c
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Sun Oct 3 23:21:13 2021 +0200

    decrease diff with upstream

commit 40da88e9ca
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Sun Oct 3 22:56:14 2021 +0200

    try to get disks to show

commit eaf2bb56a5
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Sun Oct 3 22:42:01 2021 +0200

    don't crash on deque::back()

commit f66b6f712c
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Sun Oct 3 22:08:21 2021 +0200

    cpu freq, name & process uid/name

commit 34a8a61f4d
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Sun Oct 3 21:46:11 2021 +0200

    basic process info

commit 29bb2dcc5f
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Sun Oct 3 21:45:39 2021 +0200

    initialize mutex (needed on macos apparently and not on linux)

commit fb5970b000
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Sat Oct 2 23:53:41 2021 +0200

    comment

commit 49d16cdddd
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Sat Oct 2 23:51:29 2021 +0200

    extract delimiters

commit 3db9d66476
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Sat Oct 2 23:48:28 2021 +0200

    first infos on macos: memory used & free

commit f8acb2f854
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Tue Sep 28 23:37:03 2021 +0200

    make it compile on macos (M1 - arm64). Does not run though

commit bbba17cd35
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Wed Oct 6 10:51:36 2021 +0200

    all disks + load averages

commit 548203e93d
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Wed Oct 6 10:33:55 2021 +0200

    show all disks

commit 0ab2be3985
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Wed Oct 6 00:17:41 2021 +0200

    procs sorting/filtering

commit 096104c90b
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Tue Oct 5 23:42:17 2021 +0200

    battery states

commit 0ad93684c2
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Tue Oct 5 23:24:59 2021 +0200

    battery hack works on M1

commit c75b0f1cea
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Tue Oct 5 23:18:22 2021 +0200

    ugly hack to get battery

commit 600b4f72b3
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Tue Oct 5 22:42:42 2021 +0200

    CPU stuff

commit 4eb812d52c
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Tue Oct 5 21:25:42 2021 +0200

    network

commit 899be68a78
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Tue Oct 5 15:43:05 2021 +0200

    correct cached size

commit a1c7f935e3
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Tue Oct 5 12:03:48 2021 +0200

    vm stats from syscall + swap

commit bd1050a740
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Tue Oct 5 10:48:07 2021 +0200

    seems to work indeed

commit 5094b73758
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Tue Oct 5 10:46:14 2021 +0200

    allow override optimization flag

commit 8811270332
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Tue Oct 5 10:09:24 2021 +0200

    update Makefile

commit 42f966f448
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Mon Oct 4 15:32:55 2021 +0200

    some more params

commit c1e6d6a62e
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Mon Oct 4 15:15:55 2021 +0200

    show more disks

commit 50fcdaa854
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Mon Oct 4 14:52:56 2021 +0200

    disks show something

commit 264bf2d7da
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Mon Oct 4 09:15:35 2021 +0200

    reformat

commit 1fd625086b
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Sun Oct 3 23:21:13 2021 +0200

    decrease diff with upstream

commit 17f9f3703c
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Sun Oct 3 22:56:14 2021 +0200

    try to get disks to show

commit 8462ae6431
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Sun Oct 3 22:42:01 2021 +0200

    don't crash on deque::back()

commit 78bce5b5a6
Merge: 53e379d f9505a4
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Sun Oct 3 22:08:34 2021 +0200

    Merge branch 'aristocratos:main' into main

commit 53e379d74d
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Sun Oct 3 22:08:21 2021 +0200

    cpu freq, name & process uid/name

commit 2a44b307ef
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Sun Oct 3 21:46:11 2021 +0200

    basic process info

commit 66534eb5b5
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Sun Oct 3 21:45:39 2021 +0200

    initialize mutex (needed on macos apparently and not on linux)

commit 0983917f26
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Sat Oct 2 23:53:41 2021 +0200

    comment

commit 9732507248
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Sat Oct 2 23:51:29 2021 +0200

    extract delimiters

commit 6e704ce838
Merge: fe4db7c 7bfbd83
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Sat Oct 2 23:48:43 2021 +0200

    Merge branch 'main' of github.com:joske/btop

commit fe4db7c16c
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Sat Oct 2 23:48:28 2021 +0200

    first infos on macos: memory used & free

commit 7bfbd83a47
Merge: 8c8139b a15f961
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Fri Oct 1 17:05:26 2021 +0200

    Merge branch 'aristocratos:main' into main

commit 8c8139bd1d
Merge: 679d21c a246c09
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Wed Sep 29 21:50:00 2021 +0200

    Merge branch 'aristocratos:main' into main

commit 679d21cd22
Merge: 4c70c5b a49b8f9
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Wed Sep 29 20:23:34 2021 +0200

    Merge branch 'aristocratos:main' into main

commit 4c70c5bdd9
Merge: 84a9746 c70667e
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Wed Sep 29 08:30:05 2021 +0200

    Merge branch 'aristocratos:main' into main

commit 84a974695a
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Tue Sep 28 23:37:03 2021 +0200

    make it compile on macos (M1 - arm64). Does not run though
2022-01-12 00:04:26 +01:00

959 lines
30 KiB
C++

/* Copyright 2021 Aristocratos (jakob@qvantnet.com)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
indent = tab
tab-size = 4
*/
#include <csignal>
#include <clocale>
#include <pthread.h>
#ifdef __FreeBSD__
#include <pthread_np.h>
#endif
#include <thread>
#include <numeric>
#include <ranges>
#include <unistd.h>
#include <cmath>
#include <iostream>
#include <exception>
#include <tuple>
#include <regex>
#include <chrono>
#ifdef __APPLE__
#include <CoreFoundation/CoreFoundation.h>
#endif
#include <btop_shared.hpp>
#include <btop_tools.hpp>
#include <btop_config.hpp>
#include <btop_input.hpp>
#include <btop_theme.hpp>
#include <btop_draw.hpp>
#include <btop_menu.hpp>
using std::string, std::string_view, std::vector, std::atomic, std::endl, std::cout, std::min, std::flush, std::endl;
using std::string_literals::operator""s, std::to_string;
namespace fs = std::filesystem;
namespace rng = std::ranges;
using namespace Tools;
using namespace std::chrono_literals;
namespace Global {
const vector<array<string, 2>> Banner_src = {
{"#E62525", "██████╗ ████████╗ ██████╗ ██████╗"},
{"#CD2121", "██╔══██╗╚══██╔══╝██╔═══██╗██╔══██╗ ██╗ ██╗"},
{"#B31D1D", "██████╔╝ ██║ ██║ ██║██████╔╝ ██████╗██████╗"},
{"#9A1919", "██╔══██╗ ██║ ██║ ██║██╔═══╝ ╚═██╔═╝╚═██╔═╝"},
{"#801414", "██████╔╝ ██║ ╚██████╔╝██║ ╚═╝ ╚═╝"},
{"#000000", "╚═════╝ ╚═╝ ╚═════╝ ╚═╝"},
};
const string Version = "1.1.4";
int coreCount;
string overlay;
string clock;
string bg_black = "\x1b[0;40m";
string fg_white = "\x1b[1;97m";
string fg_green = "\x1b[1;92m";
string fg_red = "\x1b[0;91m";
uid_t real_uid, set_uid;
fs::path self_path;
string exit_error_msg;
atomic<bool> thread_exception (false);
bool debuginit = false;
bool debug = false;
bool utf_force = false;
uint64_t start_time;
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;
bool arg_low_color = false;
int arg_preset = -1;
}
//* A simple argument parser
void argumentParser(const int& argc, char **argv) {
for(int i = 1; i < argc; i++) {
const string argument = argv[i];
if (is_in(argument, "-h", "--help")) {
cout << "usage: btop [-h] [-v] [-/+t] [-p <id>] [--utf-force] [--debug]\n\n"
<< "optional arguments:\n"
<< " -h, --help show this help message and exit\n"
<< " -v, --version show version info and exit\n"
<< " -lc, --low-color disable truecolor, converts 24-bit colors to 256-color\n"
<< " -t, --tty_on force (ON) tty mode, max 16 colors and tty friendly graph symbols\n"
<< " +t, --tty_off force (OFF) tty mode\n"
<< " -p, --preset <id> start with preset, integer value between 0-9\n"
<< " --utf-force force start even if no UTF-8 locale was detected\n"
<< " --debug start in DEBUG mode: shows microsecond timer for information collect\n"
<< " and screen draw functions and sets loglevel to DEBUG\n"
<< endl;
exit(0);
}
else if (is_in(argument, "-v", "--version")) {
cout << "btop version: " << Global::Version << endl;
exit(0);
}
else if (is_in(argument, "-lc", "--low-color")) {
Global::arg_low_color = true;
}
else if (is_in(argument, "-t", "--tty_on")) {
Config::set("tty_mode", true);
Global::arg_tty = true;
}
else if (is_in(argument, "+t", "--tty_off")) {
Config::set("tty_mode", false);
Global::arg_tty = true;
}
else if (is_in(argument, "-p", "--preset")) {
if (++i >= argc) {
cout << "ERROR: Preset option needs an argument." << endl;
exit(1);
}
else if (const string val = argv[i]; isint(val) and val.size() == 1) {
Global::arg_preset = std::clamp(stoi(val), 0, 9);
}
else {
cout << "ERROR: Preset option only accepts an integer value between 0-9." << endl;
exit(1);
}
}
else if (argument == "--utf-force")
Global::utf_force = true;
else if (argument == "--debug")
Global::debug = true;
else {
cout << " Unknown argument: " << argument << "\n" <<
" Use -h or --help for help." << endl;
exit(1);
}
}
}
//* Handler for SIGWINCH and general resizing events, does nothing if terminal hasn't been resized unless force=true
void term_resize(bool force) {
static atomic<bool> resizing (false);
atomic_lock lck(resizing, true);
if (auto refreshed = Term::refresh(true); refreshed or force) {
if (force and refreshed) force = false;
}
else return;
static const array<string, 4> all_boxes = {"cpu", "mem", "net", "proc"};
Global::resized = true;
if (Runner::active) Runner::stop();
Term::refresh();
Config::unlock();
auto boxes = Config::getS("shown_boxes");
auto min_size = Term::get_min_size(boxes);
while (not force or (Term::width < min_size.at(0) or Term::height < min_size.at(1))) {
sleep_ms(100);
if (Term::width < min_size.at(0) or Term::height < min_size.at(1)) {
cout << Term::clear << Global::bg_black << Global::fg_white << Mv::to((Term::height / 2) - 2, (Term::width / 2) - 11)
<< "Terminal size too small:" << Mv::to((Term::height / 2) - 1, (Term::width / 2) - 10)
<< " Width = " << (Term::width < min_size.at(1) ? Global::fg_red : Global::fg_green) << Term::width
<< Global::fg_white << " Height = " << (Term::height < min_size.at(0) ? Global::fg_red : Global::fg_green) << Term::height
<< Mv::to((Term::height / 2) + 1, (Term::width / 2) - 12) << Global::fg_white
<< "Needed for current config:" << Mv::to((Term::height / 2) + 2, (Term::width / 2) - 10)
<< "Width = " << min_size.at(0) << " Height = " << min_size.at(1) << flush;
while (not Term::refresh() and not Input::poll()) sleep_ms(10);
if (Input::poll()) {
auto key = Input::get();
if (key == "q")
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));
boxes = Config::getS("shown_boxes");
}
}
min_size = Term::get_min_size(boxes);
}
else if (not Term::refresh()) break;
}
Input::interrupt = true;
}
//* Exit handler; stops threads, restores terminal and saves config changes
void clean_quit(int sig) {
if (Global::quitting) return;
Global::quitting = true;
Runner::stop();
if (Global::_runner_started) {
#ifdef __APPLE__
if (pthread_join(Runner::runner_id, NULL) != 0) {
Logger::error("Failed to join _runner thread!");
pthread_cancel(Runner::runner_id);
}
#else
struct timespec ts;
ts.tv_sec = 5;
if (pthread_timedjoin_np(Runner::runner_id, NULL, &ts) != 0) {
Logger::error("Failed to join _runner thread!");
pthread_cancel(Runner::runner_id);
}
#endif
}
Config::write();
//? 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++) {
sleep_ms(10);
}
if (Term::initialized) {
Input::clear();
Term::restore();
}
if (not Global::exit_error_msg.empty()) {
sig = 1;
Logger::error(Global::exit_error_msg);
std::cerr << Global::fg_red << "ERROR: " << Global::fg_white << Global::exit_error_msg << Fx::reset << endl;
}
Logger::info("Quitting! Runtime: " + sec_to_dhms(time_s() - Global::start_time));
const auto excode = (sig != -1 ? sig : 0);
//? Assume error if still not cleaned up and call quick_exit to avoid a segfault from Tools::atomic_lock destructor
#ifdef __APPLE__
_Exit(excode);
#else
quick_exit(excode);
#endif
}
//* Handler for SIGTSTP; stops threads, restores terminal and sends SIGSTOP
void _sleep() {
Runner::stop();
Term::restore();
std::raise(SIGSTOP);
}
//* Handler for SIGCONT; re-initialize terminal and force a resize event
void _resume() {
Term::init();
term_resize(true);
}
void _exit_handler() {
clean_quit(-1);
}
void _signal_handler(const int sig) {
switch (sig) {
case SIGINT:
if (Runner::active) {
Global::should_quit = true;
Runner::stopping = true;
Input::interrupt = true;
}
else {
clean_quit(0);
}
break;
case SIGTSTP:
if (Runner::active) {
Global::should_sleep = true;
Runner::stopping = true;
Input::interrupt = true;
}
else {
_sleep();
}
break;
case SIGCONT:
_resume();
break;
case SIGWINCH:
term_resize();
break;
}
}
//* Manages secondary thread for collection and drawing of boxes
namespace Runner {
atomic<bool> active (false);
atomic<bool> stopping (false);
atomic<bool> waiting (false);
atomic<bool> redraw (false);
//* Setup semaphore for triggering thread to do work
#if __GNUC__ < 11
#include <semaphore.h>
sem_t do_work;
inline void thread_sem_init() { sem_init(&do_work, 0, 0); }
inline void thread_wait() { sem_wait(&do_work); }
inline void thread_trigger() { sem_post(&do_work); }
#else
#include <semaphore>
std::binary_semaphore do_work(0);
inline void thread_sem_init() { ; }
inline void thread_wait() { do_work.acquire(); }
inline void thread_trigger() { do_work.release(); }
#endif
//* RAII wrapper for pthread_mutex locking
class thread_lock {
pthread_mutex_t& pt_mutex;
public:
int status;
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;
sigset_t mask;
pthread_t runner_id;
pthread_mutex_t mtx;
enum debug_actions {
collect_begin,
draw_begin,
draw_done
};
enum debug_array {
collect,
draw
};
string debug_bg;
unordered_flat_map<string, array<uint64_t, 2>> debug_times;
struct runner_conf {
vector<string> boxes;
bool no_update;
bool force_redraw;
bool background_update;
string overlay;
string clock;
};
struct runner_conf current_conf;
void debug_timer(const char* name, const int action) {
switch (action) {
case collect_begin:
debug_times[name].at(collect) = time_micros();
return;
case draw_begin:
debug_times[name].at(draw) = time_micros();
debug_times[name].at(collect) = debug_times[name].at(draw) - debug_times[name].at(collect);
debug_times["total"].at(collect) += debug_times[name].at(collect);
return;
case draw_done:
debug_times[name].at(draw) = time_micros() - debug_times[name].at(draw);
debug_times["total"].at(draw) += debug_times[name].at(draw);
return;
}
}
//? ------------------------------- Secondary thread: async launcher and drawing ----------------------------------
void * _runner(void * _) {
(void)_;
//? 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, SIGWINCH);
sigaddset(&mask, SIGTERM);
pthread_sigmask(SIG_BLOCK, &mask, NULL);
//? pthread_mutex_lock to lock thread and monitor health from main thread
thread_lock pt_lck(mtx);
if (pt_lck.status != 0) {
Global::exit_error_msg = "Exception in runner thread -> pthread_mutex_lock error id: " + to_string(pt_lck.status);
Global::thread_exception = true;
Input::interrupt = true;
stopping = true;
}
//* ----------------------------------------------- THREAD LOOP -----------------------------------------------
while (not Global::quitting) {
thread_wait();
atomic_wait_for(active, true, 5000);
if (active) {
Global::exit_error_msg = "Runner thread failed to get active lock!";
Global::thread_exception = true;
Input::interrupt = true;
stopping = true;
}
if (stopping or Global::resized) {
sleep_ms(1);
continue;
}
//? 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
if (Global::debug) {
if (debug_bg.empty() or redraw) Runner::debug_bg = Draw::createBox(2, 2, 32, 8, "", true, "debug");
debug_times.clear();
debug_times["total"] = {0, 0};
}
output.clear();
//* Run collection and draw functions for all boxes
try {
//? CPU
if (v_contains(conf.boxes, "cpu")) {
try {
if (Global::debug) debug_timer("cpu", collect_begin);
//? Start collect
auto cpu = Cpu::collect(conf.no_update);
if (Global::debug) debug_timer("cpu", draw_begin);
//? Draw box
if (not pause_output) output += Cpu::draw(cpu, conf.force_redraw, conf.no_update);
if (Global::debug) debug_timer("cpu", draw_done);
}
catch (const std::exception& e) {
throw std::runtime_error("Cpu:: -> " + (string)e.what());
}
}
//? MEM
if (v_contains(conf.boxes, "mem")) {
try {
if (Global::debug) debug_timer("mem", collect_begin);
//? Start collect
auto mem = Mem::collect(conf.no_update);
if (Global::debug) debug_timer("mem", draw_begin);
//? Draw box
if (not pause_output) output += Mem::draw(mem, conf.force_redraw, conf.no_update);
if (Global::debug) debug_timer("mem", draw_done);
}
catch (const std::exception& e) {
throw std::runtime_error("Mem:: -> " + (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());
}
}
//? 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());
}
}
}
catch (const std::exception& e) {
Global::exit_error_msg = "Exception in runner thread -> " + (string)e.what();
Global::thread_exception = true;
Input::interrupt = true;
stopping = true;
}
if (stopping) {
continue;
}
if (redraw or conf.force_redraw) {
empty_bg.clear();
redraw = false;
}
if (not pause_output) output += conf.clock;
if (not conf.overlay.empty() and not conf.background_update) pause_output = true;
if (output.empty() and not pause_output) {
if (empty_bg.empty()) {
const int x = Term::width / 2 - 10, y = Term::height / 2 - 10;
output += Term::clear;
empty_bg += Draw::banner_gen(y, 0, true)
+ Mv::to(y+6, x) + Theme::c("title") + Fx::b + "No boxes shown!"
+ Mv::to(y+8, x) + Theme::c("hi_fg") + "1" + Theme::c("main_fg") + " | Show CPU box"
+ Mv::to(y+9, x) + Theme::c("hi_fg") + "2" + Theme::c("main_fg") + " | Show MEM box"
+ Mv::to(y+10, x) + Theme::c("hi_fg") + "3" + Theme::c("main_fg") + " | Show NET box"
+ Mv::to(y+11, x) + Theme::c("hi_fg") + "4" + Theme::c("main_fg") + " | Show PROC box"
+ Mv::to(y+12, x-2) + Theme::c("hi_fg") + "esc" + Theme::c("main_fg") + " | Show menu"
+ Mv::to(y+13, x) + Theme::c("hi_fg") + "q" + Theme::c("main_fg") + " | Quit";
}
output += empty_bg;
}
//! DEBUG stats -->
if (Global::debug and not Menu::active) {
output += debug_bg + Theme::c("title") + Fx::b + ljust(" Box", 9) + ljust("Collect μs", 12, true) + ljust("Draw μs", 9, true) + Theme::c("main_fg") + Fx::ub;
for (const string name : {"cpu", "mem", "net", "proc", "total"}) {
if (not debug_times.contains(name)) debug_times[name] = {0,0};
const auto& [time_collect, time_draw] = debug_times.at(name);
if (name == "total") output += Fx::b;
output += Mv::l(29) + Mv::d(1) + ljust(name, 8) + ljust(to_string(time_collect), 12) + ljust(to_string(time_draw), 9);
}
}
//? If overlay isn't empty, print output without color and then print overlay on top
cout << Term::sync_start << (conf.overlay.empty()
? output
: (output.empty() ? "" : Fx::ub + Theme::c("inactive_fg") + Fx::uncolor(output)) + conf.overlay)
<< Term::sync_end << flush;
}
//* ----------------------------------------------- THREAD LOOP -----------------------------------------------
pthread_exit(NULL);
}
//? ------------------------------------------ Secondary thread end -----------------------------------------------
//* Runs collect and draw in a secondary thread, unlocks and locks config to update cached values
void run(const string& box, const bool no_update, const bool force_redraw) {
atomic_wait_for(active, true, 5000);
if (active) {
Logger::error("Stall in Runner thread, restarting!");
active = false;
// exit(1);
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!";
clean_quit(1);
}
}
if (stopping or Global::resized) return;
if (box == "overlay") {
cout << Term::sync_start << Global::overlay << Term::sync_end << flush;
}
else if (box == "clock") {
cout << Term::sync_start << Global::clock << Term::sync_end << flush;
}
else {
Config::unlock();
Config::lock();
current_conf = {
(box == "all" ? Config::current_boxes : vector{box}),
no_update, force_redraw,
(not Config::getB("tty_mode") and Config::getB("background_update")),
Global::overlay,
Global::clock
};
if (Menu::active and not current_conf.background_update) Global::overlay.clear();
thread_trigger();
atomic_wait_for(active, false, 10);
}
}
//* Stops any work being done in runner thread and checks for thread errors
void stop() {
stopping = true;
int ret = pthread_mutex_trylock(&mtx);
if (ret != EBUSY and not Global::quitting) {
if (active) active = false;
Global::exit_error_msg = "Runner thread died unexpectedly!";
clean_quit(1);
}
else if (ret == EBUSY) {
atomic_wait_for(active, true, 5000);
if (active) {
active = false;
if (Global::quitting) {
return;
}
else {
Global::exit_error_msg = "No response from Runner thread, quitting!";
clean_quit(1);
}
}
thread_trigger();
atomic_wait_for(active, false, 100);
atomic_wait_for(active, true, 100);
}
stopping = false;
}
}
//* --------------------------------------------- Main starts here! ---------------------------------------------------
int main(int argc, char **argv) {
//? ------------------------------------------------ INIT ---------------------------------------------------------
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);
//? Setup paths for config, log and user themes
for (const auto& env : {"XDG_CONFIG_HOME", "HOME"}) {
if (std::getenv(env) != NULL and access(std::getenv(env), W_OK) != -1) {
Config::conf_dir = fs::path(std::getenv(env)) / (((string)env == "HOME") ? ".config/btop" : "btop");
break;
}
}
if (Config::conf_dir.empty()) {
cout << "WARNING: Could not get path user HOME folder.\n"
<< "Make sure $XDG_CONFIG_HOME or $HOME environment variables is correctly set to fix this." << endl;
}
else {
if (std::error_code ec; not fs::is_directory(Config::conf_dir) and not fs::create_directories(Config::conf_dir, ec)) {
cout << "WARNING: Could not create or access btop config directory. Logging and config saving disabled.\n"
<< "Make sure $XDG_CONFIG_HOME or $HOME environment variables is correctly set to fix this." << endl;
}
else {
Config::conf_file = Config::conf_dir / "btop.conf";
Logger::logfile = Config::conf_dir / "btop.log";
Theme::user_theme_dir = Config::conf_dir / "themes";
if (not fs::exists(Theme::user_theme_dir) and not fs::create_directory(Theme::user_theme_dir, ec)) Theme::user_theme_dir.clear();
}
}
//? Try to find global btop theme path relative to binary path
#if defined(__linux__)
{ std::error_code ec;
Global::self_path = fs::read_symlink("/proc/self/exe", ec).remove_filename();
}
#endif
if (std::error_code ec; not Global::self_path.empty()) {
Theme::theme_dir = fs::canonical(Global::self_path / "../share/btop/themes", ec);
if (ec or not fs::is_directory(Theme::theme_dir) or access(Theme::theme_dir.c_str(), R_OK) == -1) Theme::theme_dir.clear();
}
//? If relative path failed, check two most common absolute paths
if (Theme::theme_dir.empty()) {
for (auto theme_path : {"/usr/local/share/btop/themes", "/usr/share/btop/themes"}) {
if (fs::is_directory(fs::path(theme_path)) and access(theme_path, R_OK) != -1) {
Theme::theme_dir = fs::path(theme_path);
break;
}
}
}
//? Config init
{ vector<string> load_warnings;
Config::load(Config::conf_file, load_warnings);
if (Config::current_boxes.empty()) Config::check_boxes(Config::getS("shown_boxes"));
Config::set("lowcolor", (Global::arg_low_color ? true : not Config::getB("truecolor")));
if (Global::debug) {
Logger::set("DEBUG");
Logger::debug("Starting in DEBUG mode!");
}
else Logger::set(Config::getS("log_level"));
Logger::info("Logger set to " + (Global::debug ? "DEBUG" : Config::getS("log_level")));
for (const auto& err_str : load_warnings) Logger::warning(err_str);
}
//? Try to find and set a UTF-8 locale
if (std::setlocale(LC_ALL, "") != NULL and not s_contains((string)std::setlocale(LC_ALL, ""), ";")
and str_to_upper(s_replace((string)std::setlocale(LC_ALL, ""), "-", "")).ends_with("UTF8")) {
Logger::debug("Using locale " + (string)std::setlocale(LC_ALL, ""));
}
else {
string found;
bool set_failure = false;
for (const auto loc_env : array{"LANG", "LC_ALL"}) {
if (std::getenv(loc_env) != NULL and str_to_upper(s_replace((string)std::getenv(loc_env), "-", "")).ends_with("UTF8")) {
found = std::getenv(loc_env);
if (std::setlocale(LC_ALL, found.c_str()) == NULL) {
set_failure = true;
Logger::warning("Failed to set locale " + found + " continuing anyway.");
}
}
}
if (found.empty()) {
if (setenv("LC_ALL", "", 1) == 0 and setenv("LANG", "", 1) == 0) {
try {
if (const auto loc = std::locale("").name(); not loc.empty() and loc != "*") {
for (auto& l : ssplit(loc, ';')) {
if (str_to_upper(s_replace(l, "-", "")).ends_with("UTF8")) {
found = l.substr(l.find('=') + 1);
if (std::setlocale(LC_ALL, found.c_str()) != NULL) {
break;
}
}
}
}
}
catch (...) { found.clear(); }
}
}
#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);
}
//? Initialize terminal and set options
if (not Term::init()) {
Global::exit_error_msg = "No tty detected!\nbtop++ needs an interactive shell to run.";
clean_quit(1);
}
if (Term::current_tty != "unknown") Logger::info("Running on " + Term::current_tty);
if (not Global::arg_tty and Config::getB("force_tty")) {
Config::set("tty_mode", true);
Logger::info("Forcing tty mode: setting 16 color mode and using tty friendly graph symbols");
}
#ifndef __APPLE__
else if (not Global::arg_tty and Term::current_tty.starts_with("/dev/tty")) {
Config::set("tty_mode", true);
Logger::info("Real tty detected: setting 16 color mode and using tty friendly graph symbols");
}
#endif
//? Check for valid terminal dimensions
{
int t_count = 0;
while (Term::width <= 0 or Term::width > 10000 or Term::height <= 0 or Term::height > 10000) {
sleep_ms(10);
Term::refresh();
if (++t_count == 100) {
Global::exit_error_msg = "Failed to get size of terminal!";
clean_quit(1);
}
}
}
//? Platform dependent init and error check
try {
Shared::init();
}
catch (const std::exception& e) {
Global::exit_error_msg = "Exception in Shared::init() -> " + (string)e.what();
clean_quit(1);
}
//? Update list of available themes and generate the selected theme
Theme::updateThemes();
Theme::setTheme();
//? Setup signal handlers for CTRL-C, CTRL-Z, resume and terminal resize
std::atexit(_exit_handler);
std::signal(SIGINT, _signal_handler);
std::signal(SIGTSTP, _signal_handler);
std::signal(SIGCONT, _signal_handler);
std::signal(SIGWINCH, _signal_handler);
//? Start runner thread
Runner::thread_sem_init();
if (pthread_create(&Runner::runner_id, NULL, &Runner::_runner, NULL) != 0) {
Global::exit_error_msg = "Failed to create _runner thread!";
clean_quit(1);
}
else {
Global::_runner_started = true;
}
//? Calculate sizes of all boxes
Config::presetsValid(Config::getS("presets"));
if (Global::arg_preset >= 0) {
Config::current_preset = min(Global::arg_preset, (int)Config::preset_list.size() - 1);
Config::apply_preset(Config::preset_list.at(Config::current_preset));
}
{
const auto [x, y] = Term::get_min_size(Config::getS("shown_boxes"));
if (Term::height < y or Term::width < x) {
term_resize(true);
Global::resized = false;
Input::interrupt = false;
}
}
Draw::calcSizes();
//? Print out box outlines
cout << Term::sync_start << Cpu::box << Mem::box << Net::box << Proc::box << Term::sync_end << flush;
//? ------------------------------------------------ MAIN LOOP ----------------------------------------------------
uint64_t update_ms = Config::getI("update_ms");
auto future_time = time_ms();
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) 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();
//? Trigger secondary thread to redraw if terminal has been resized
if (Global::resized) {
Draw::calcSizes();
Draw::update_clock(true);
Global::resized = false;
if (Menu::active) Menu::process();
else Runner::run("all", true, true);
atomic_wait_for(Runner::active, true, 1000);
}
//? Update clock if needed
if (Draw::update_clock() and not Menu::active) {
Runner::run("clock");
}
//? Start secondary collect & draw thread at the interval set by <update_ms> config value
if (time_ms() >= future_time and not Global::resized) {
Runner::run("all");
update_ms = Config::getI("update_ms");
future_time = time_ms() + update_ms;
}
//? Loop over input polling and input action processing
for (auto current_time = time_ms(); current_time < future_time; current_time = time_ms()) {
//? Check for external clock changes and for changes to the update timer
if (std::cmp_not_equal(update_ms, Config::getI("update_ms"))) {
update_ms = Config::getI("update_ms");
future_time = time_ms() + update_ms;
}
else if (future_time - current_time > update_ms)
future_time = current_time;
//? Poll for input and process any input detected
else if (Input::poll(min((uint64_t)1000, future_time - current_time))) {
if (not Runner::active) Config::unlock();
if (Menu::active) Menu::process(Input::get());
else Input::process(Input::get());
}
//? Break the loop at 1000ms intervals or if input polling was interrupted
else break;
}
}
}
catch (const std::exception& e) {
Global::exit_error_msg = "Exception in main loop -> " + (string)e.what();
clean_quit(1);
}
}