From 2acae992142547472d754ad6f8844763b254b928 Mon Sep 17 00:00:00 2001 From: Ian Kelling Date: Mon, 15 Jun 2026 15:19:24 -0400 Subject: [PATCH] mostly simply btrfsmaint, add multiple emacs daemon features --- brc2 | 2 +- btrfsmaint | 150 +++++------------- conflink | 2 +- distro-end | 7 +- filesystem/etc/prometheus/rules/iank.yml | 4 +- filesystem/etc/sudoers.d/iank | 1 + .../etc/systemd/system/btrfsmaint.service | 3 +- .../etc/systemd/system/btrfsmaint.timer | 2 +- .../etc/systemd/system/btrfsmaintstop.service | 13 -- g | 62 +------- g-lib.sh | 65 ++++++++ g2 | 11 +- g3 | 32 ++++ g4 | 32 ++++ install-my-scripts | 3 - system-status | 1 - 16 files changed, 197 insertions(+), 193 deletions(-) create mode 100644 filesystem/etc/sudoers.d/iank delete mode 100644 filesystem/etc/systemd/system/btrfsmaintstop.service create mode 100755 g-lib.sh create mode 100755 g3 create mode 100755 g4 diff --git a/brc2 b/brc2 index e67c8cd..a5daa4b 100644 --- a/brc2 +++ b/brc2 @@ -2009,7 +2009,7 @@ ccomp xdg-open o # jfilter() { # grep -Evi -e "^(\S+\s+){4}(sudo|sshd|cron)\[\S*:" \ - # -e "^(\S+\s+){4}systemd\[\S*: (starting|started) (btrfsmaintstop|dynamicipupdate|spamd dns bug fix cronjob|rss2email)\.*$" + # -e "^(\S+\s+){4}systemd\[\S*: (starting|started) (dynamicipupdate|spamd dns bug fix cronjob|rss2email)\.*$" # } # jtail() { # journalctl -n 10000 -f "$@" | jfilter diff --git a/btrfsmaint b/btrfsmaint index 8f56e4c..e6f0814 100755 --- a/btrfsmaint +++ b/btrfsmaint @@ -43,18 +43,6 @@ EOF fi -check-idle() { - type -p xscreensaver-command &>/dev/null || return 0 - export XAUTHORITY=/home/iank/.Xauthority - export DISPLAY=:0 - locked=false - if lock_info=$(xscreensaver-command -time 2>/dev/null); then - if [[ $lock_info != *non-blanked* ]]; then - locked=true - fi - fi -} - usage() { cat <$stats_path ||: # populate initial reading - elif ! btrfs dev stats -c $mnt >$tmp; then - if ! diff -q $stats_path $tmp; then - mv $stats_path $stats_path.1 - cat $tmp >$stats_path - diff=$(diff -u $stats_path $tmp 2>&1 ||:) - printf "diff of: btrfs dev stats -c %s\n%s\n" "$mnt" "$diff" - exim -odf -i root <$stats_path ||: # populate initial reading + elif ! btrfs dev stats -c $mnt >$tmp; then + if ! diff -q $stats_path $tmp; then + mv $stats_path $stats_path.1 + cat $tmp >$stats_path + diff=$(diff -u $stats_path $tmp 2>&1 ||:) + printf "diff of: btrfs dev stats -c %s\n%s\n" "$mnt" "$diff" + exim -odf -i root </dev/null + # only documented in source code. wonderful. takes care of balance for us. + echo 1 | tee /sys/fs/btrfs/*/allocation/data/periodic_reclaim >/dev/null - date= + t_start= scrub_status=$(btrfs scrub status $mnt) - if printf "%s\n" "$scrub_status" | grep -i '^status:[[:space:]]*finished$' &>/dev/null; then - date=$(printf "%s\n" "$scrub_status" | sed -rn 's/^Scrub started:[[:space:]]*(.*)/\1/p') - fi - if [[ ! $date ]]; then - # output from older versions, at least btrfs v4.15.1 - date=$( - printf "%s\n" "$scrub_status" | \ - sed -rn 's/^\s*scrub started at (.*) and finished.*/\1/p' - ) + start_cmd=start + if printf "%s\n" "$scrub_status" | grep -iE '^status:[[:space:]]*(aborted|interrupted)$' &>/dev/null; then + start_cmd=resume + elif printf "%s\n" "$scrub_status" | grep -i '^status:[[:space:]]*finished$' &>/dev/null; then + t_start=$(sed -rn 's/.*t_start:([0-9]+).*/\1/p' /var/lib/btrfs/scrub.status.$uuid | sort -n | tail -n1) fi - if [[ $date ]]; then + if [[ $t_start ]]; then if $dry_run; then - echo "$0: last scrub finish for $mnt: $date" + echo "$0: last scrub finish for $mnt: $t_start" fi - date=$(date --date="$date" +%s) # if date is sooner than 60 days ago # the wiki recommends 30 days or so, but # I'm going with 60 days. - if (( date > EPOCHSECONDS - 60*60*24*60 )); then + if (( t_start > EPOCHSECONDS - 60*60*24*60 )); then if $dry_run; then - echo "$0: skiping scrub of $mnt, last was $(( (EPOCHSECONDS - date) / 60/60/24 )) days ago, < 30 days" + echo "$0: skiping scrub of $mnt, last was $(( (EPOCHSECONDS - t_start) / 60/60/24 )) days ago, < 60 days" fi continue fi fi - # btrfsmaintenance does -c 2 -n 4, but I want lowest pri. - dr btrfs scrub start -Bd -c 3 $mnt - - # We normally only do one disk since this is meant to be run in - # downtime and if we try to do all disks, we invariably end up doing - # a scrub after downtime. So, just do one disk per day. - if ! $force; then - return 0 + # 20m = 11 days for a 20 tb hd. + # dynamic way to set the limit is: + # -B means don't background. this allows us to run just one at a time. + if $dry_run; then + echo "$0: dry run. would run btrfs scrub $start_cmd -Bd -c 3 $mnt + fstrim" + else + echo 20m | tee /sys/fs/btrfs/$uuid/devinfo/*/scrub_speed_max >/dev/null + sleep 1 # just paranoid + # note: --limit in man page is buggy, sets it only on some devices, but without it, sets it to 0. + m btrfs scrub $start_cmd --limit 20m -Bd $mnt + m fstrim $mnt fi done } -loop-main() { - while true; do - main - sleep 60 - done -} - -if $check; then - loop-main -else - main -fi +main diff --git a/conflink b/conflink index e6c9477..b303d53 100755 --- a/conflink +++ b/conflink @@ -109,7 +109,7 @@ common-file-setup() { old-files-cleanup() { # old files 2022-03 - for t in systemstatus epanicclean btrfsmaintstop dynamicipupdate; do + for t in systemstatus epanicclean dynamicipupdate; do f=/etc/systemd/system/$t.timer if [[ -e $f ]]; then v systemctl stop $t.timer diff --git a/distro-end b/distro-end index eda39db..1b66a78 100755 --- a/distro-end +++ b/distro-end @@ -1794,9 +1794,12 @@ EOF sysd-prom-fail-install dynamicipupdate sysd-prom-fail-install systemstatus -sysd-prom-fail-install btrfsmaintstop +sysd-prom-fail-install btrfsmaint sgo btrfsmaint.timer -sgo btrfsmaintstop +if [[ -e /etc/systemd/system/btrfsmaintstop.service ]]; then + soff btrfsmaintstop + sudo rm -rf /etc/systemd/system/btrfsmaintstop.service* +fi sgo systemstatus sgo dynamicipupdate diff --git a/filesystem/etc/prometheus/rules/iank.yml b/filesystem/etc/prometheus/rules/iank.yml index 47012cc..4231582 100644 --- a/filesystem/etc/prometheus/rules/iank.yml +++ b/filesystem/etc/prometheus/rules/iank.yml @@ -85,7 +85,7 @@ groups: - alert: mysers_units_missing expr: |- count(up{job="node"} == 1) by (instance) * 3 unless - count(node_systemd_unit_state{name=~"(systemstatus|btrfsmaintstop|dynamicipupdate).service",state="active"}) by (instance) + count(node_systemd_unit_state{name=~"(systemstatus|dynamicipupdate).service",state="active"}) by (instance) for: 20m labels: severity: warn @@ -107,7 +107,7 @@ groups: - alert: mysers_not_active expr: |- - node_systemd_unit_state{name=~"(systemstatus|btrfsmaintstop|dynamicipupdate).service",state="active"} != 1 + node_systemd_unit_state{name=~"(systemstatus|dynamicipupdate).service",state="active"} != 1 for: 20m labels: severity: warn diff --git a/filesystem/etc/sudoers.d/iank b/filesystem/etc/sudoers.d/iank new file mode 100644 index 0000000..d5a1728 --- /dev/null +++ b/filesystem/etc/sudoers.d/iank @@ -0,0 +1 @@ +Defaults pwfeedback diff --git a/filesystem/etc/systemd/system/btrfsmaint.service b/filesystem/etc/systemd/system/btrfsmaint.service index 73fb294..5092274 100644 --- a/filesystem/etc/systemd/system/btrfsmaint.service +++ b/filesystem/etc/systemd/system/btrfsmaint.service @@ -5,6 +5,7 @@ After=multi-user.target [Service] Type=simple # note, btrfs maint is hardlinked into fsf ansible repo -ExecStart=/usr/local/bin/btrfsmaint --no-stats +ExecStart=/usr/local/bin/btrfsmaint +# note: these may make very little difference depending on scheduler. IOSchedulingClass=idle CPUSchedulingPolicy=idle diff --git a/filesystem/etc/systemd/system/btrfsmaint.timer b/filesystem/etc/systemd/system/btrfsmaint.timer index a60d347..8a4ab0b 100644 --- a/filesystem/etc/systemd/system/btrfsmaint.timer +++ b/filesystem/etc/systemd/system/btrfsmaint.timer @@ -8,7 +8,7 @@ Description=btrfsmaint # readlink /etc/localtime | sed -r 's,^.*/([^/]+/[^/]+)$,\1,' # run daily -OnCalendar=*-*-* 02:00:00 America/New_York +OnCalendar=*-*-* 18:00:00 America/New_York # previously, was running weekly: #OnCalendar=Thu *-*-* 02:00:00 America/New_York diff --git a/filesystem/etc/systemd/system/btrfsmaintstop.service b/filesystem/etc/systemd/system/btrfsmaintstop.service deleted file mode 100644 index 88f90a9..0000000 --- a/filesystem/etc/systemd/system/btrfsmaintstop.service +++ /dev/null @@ -1,13 +0,0 @@ -[Unit] -Description=btrfsmaintstop -After=local-fs.target -StartLimitIntervalSec=0 - -[Service] -Type=simple -ExecStart=/usr/local/bin/btrfsmaint --check -Restart=always -RestartSec=600 - -[Install] -WantedBy=graphical.target diff --git a/g b/g index 713735c..ac1be0b 100755 --- a/g +++ b/g @@ -21,63 +21,13 @@ # limitations under the License. +glib=${BASH_SOURCE[0]%/*}/g-lib.sh -# note: starting emacs server can hang due to errors in init files -# which don't cause problems for non-server emacs. And things -# that aren't errors can cause hang too, like when I added gnus -# git to load path. +if [[ ! -s $glib ]]; then + echo "$0: error, can't find g-lib.sh" >&2; exit 1 +fi -# note: I was experimenting with running -# under gdb always to diagnose any hangs/crashes -# and it won't work due to a gdb crash: -# gdb -ex="set follow-fork-mode child" -ex=r -ex=quit --args emacsclient -nc -# -# -n = --no-wait, go into background -# -c = create new frame instead of reusing the current frame -# -a = alternate editor, empty string makes it start emacs daemon. -# This is also set via env variable, but that doesn't propagate everywhere. - - -g() { - - local args gdb=false - - if [[ $DISPLAY ]]; then - args=-n - fi - - if (( $# == 0 )); then - args+=" -c" - fi - - id=$(i3-msg -t get_tree | jq -e '.. | select(.name?) | select(.name | test("^e-iak ")).id'| sort -n| head -n1) - - if [[ ! $id ]]; then - if (( $# == 0 )) && type -p gdb &>/dev/null; then - # no time for messing with gdb right now - #gdb=true - : - else - # duplicate arg, but oh well. - args+=" -c" - fi - fi - - if $gdb; then - # due to a bug, we cant debug from the start unless we get a new gdb - # https://sourceware.org/bugzilla/show_bug.cgi?id=24454 - # m gdb -ex="set follow-fork-mode child" -ex=r -ex=quit --args emacs --daemon - emacsclient -a "" $args "$@" - sleep 1 - cd "/a/opt/emacs-$(distro-name)$(distro-num)" - sudo gdb -p "$(pgrep -f 'emacs --daemon')" -ex c - # note: this is dead code since this is called as a script. - # shellcheck disable=SC2103 # preference for simplicity. - cd - - else - emacsclient -a "" $args "$@" - fi -} +source $glib echo "$*" >>/tmp/g.log -g "$@" +g none "$@" diff --git a/g-lib.sh b/g-lib.sh new file mode 100755 index 0000000..7fb15d9 --- /dev/null +++ b/g-lib.sh @@ -0,0 +1,65 @@ +#!/bin/bash + +# note: starting emacs server can hang due to errors in init files +# which don't cause problems for non-server emacs. And things +# that aren't errors can cause hang too, like when I added gnus +# git to load path. + +# note: I was experimenting with running +# under gdb always to diagnose any hangs/crashes +# and it won't work due to a gdb crash: +# gdb -ex="set follow-fork-mode child" -ex=r -ex=quit --args emacsclient -nc +# +# -n = --no-wait, go into background +# -c = create new frame instead of reusing the current frame +# -a = alternate editor, empty string makes it start emacs daemon. +# This is also set via env variable, but that doesn't propagate everywhere. + + +g() { + + local args gdb=false server="$1" + shift + + if [[ $DISPLAY ]]; then + args=-n + fi + + if (( $# == 0 )); then + args+=" -c" + fi + + if [[ $server == none ]]; then + server= + else + args+=" -s $server" + fi + + id=$(i3-msg -t get_tree | jq -e '.. | select(.name?) | select(.name | test("^e-'$server'iak ")).id'| sort -n| head -n1) + + if [[ ! $id ]]; then + if (( $# == 0 )) && type -p gdb &>/dev/null; then + # no time for messing with gdb right now + #gdb=true + : + else + # duplicate arg, but oh well. + args+=" -c" + fi + fi + + if $gdb; then + # due to a bug, we cant debug from the start unless we get a new gdb + # https://sourceware.org/bugzilla/show_bug.cgi?id=24454 + # m gdb -ex="set follow-fork-mode child" -ex=r -ex=quit --args emacs --daemon + emacsclient -a "" $args "$@" + sleep 1 + cd "/a/opt/emacs-$(distro-name)$(distro-num)" + sudo gdb -p "$(pgrep -f 'emacs --daemon')" -ex c + # note: this is dead code since this is called as a script. + # shellcheck disable=SC2103 # preference for simplicity. + cd - + else + emacsclient -a "" $args "$@" + fi +} diff --git a/g2 b/g2 index a6b8da7..d015f4f 100755 --- a/g2 +++ b/g2 @@ -20,6 +20,13 @@ # See the License for the specific language governing permissions and # limitations under the License. +glib=${BASH_SOURCE[0]%/*}/g-lib.sh -# force creation of new frame. -exec emacsclient -a "" -nc "$@" +if [[ ! -s $glib ]]; then + echo "$0: error, can't find g-lib.sh" >&2; exit 1 +fi + +source $glib + +echo "$*" >>/tmp/g2.log +g g2 "$@" diff --git a/g3 b/g3 new file mode 100755 index 0000000..5067e87 --- /dev/null +++ b/g3 @@ -0,0 +1,32 @@ +#!/bin/bash +# I, Ian Kelling, follow the GNU license recommendations at +# https://www.gnu.org/licenses/license-recommendations.en.html. They +# recommend that small programs, < 300 lines, be licensed under the +# Apache License 2.0. This file contains or is part of one or more small +# programs. If a small program grows beyond 300 lines, I plan to switch +# its license to GPL. + +# Copyright 2024 Ian Kelling + +# 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. + +glib=${BASH_SOURCE[0]%/*}/g-lib.sh + +if [[ ! -s $glib ]]; then + echo "$0: error, can't find g-lib.sh" >&2; exit 1 +fi + +source $glib + +echo "$*" >>/tmp/g2.log +g g3 "$@" diff --git a/g4 b/g4 new file mode 100755 index 0000000..e275235 --- /dev/null +++ b/g4 @@ -0,0 +1,32 @@ +#!/bin/bash +# I, Ian Kelling, follow the GNU license recommendations at +# https://www.gnu.org/licenses/license-recommendations.en.html. They +# recommend that small programs, < 300 lines, be licensed under the +# Apache License 2.0. This file contains or is part of one or more small +# programs. If a small program grows beyond 300 lines, I plan to switch +# its license to GPL. + +# Copyright 2024 Ian Kelling + +# 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. + +glib=${BASH_SOURCE[0]%/*}/g-lib.sh + +if [[ ! -s $glib ]]; then + echo "$0: error, can't find g-lib.sh" >&2; exit 1 +fi + +source $glib + +echo "$*" >>/tmp/g2.log +g g4 "$@" diff --git a/install-my-scripts b/install-my-scripts index 0d37653..0b774f1 100755 --- a/install-my-scripts +++ b/install-my-scripts @@ -80,9 +80,6 @@ while read -r line; do file="${line:12}" #echo debug: file: $file case $file in - btrfsmaint) - sre btrfsmaintstop - ;; mailtest-check) # we stopped removing the dashes in services recently. sre $file diff --git a/system-status b/system-status index 34ac06d..92c5b85 100755 --- a/system-status +++ b/system-status @@ -80,7 +80,6 @@ write-status() { *) services+=( systemstatus - btrfsmaintstop dynamicipupdate ) bads=() -- 2.30.2