X-Git-Url: https://iankelling.org/git/?a=blobdiff_plain;ds=inline;f=brc2;h=e936badfba828a52dcbab2c003e8b1c05bd2c65a;hb=7f9af41bd119784d4f062731911d1485d224ec73;hp=15f953909b6e2f790c28761d9053400c6a82260a;hpb=2ff8740f1061a31683152a4447340921de82b1b9;p=distro-setup
diff --git a/brc2 b/brc2
index 15f9539..e936bad 100644
--- a/brc2
+++ b/brc2
@@ -1,6 +1,25 @@
#!/bin/bash
-# Copyright (C) 2019 Ian Kelling
-# SPDX-License-Identifier: AGPL-3.0-or-later
+# 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.
+
# this gets sourced. shebang is just for file mode detection
@@ -58,6 +77,13 @@ source /a/bin/log-quiet/logq-function
source /a/bin/bash_unpublished/source-semi-priv
source /a/bin/bash_unpublished/source-state
+if [[ $HOSTNAME == "$MAIL_HOST" ]]; then
+ export MAIL_HOST_P=t
+else
+ export NOT_MAIL_HOST_P=t
+fi
+
+
source /a/bin/log-quiet/logq-function
# not used
@@ -128,6 +154,12 @@ zcheck() {
ssh bow rm /tmp/oegu.jpg
feh /t/oegu.jpg
}
+zmon() {
+ while true; do
+ ziva-screen
+ sleep 15
+ done
+}
slemacs() {
local arg rtime v
@@ -184,6 +216,20 @@ rm-docker-iptables() {
# usage mkschroot [-] distro codename packages
# - means no piping in of sources.list
+#
+# note some useful post mkschroot i've used in the past
+# tu /nocow/schroot/flidas/etc/sudoers </dev/null ||:
}
+# run if not running.
+#
+# Note: this does not work with shell scripts as they are normally
+# invoked, because the ps output has the interpreter at the start.
+# A workaround is to invoke the command in that format, or we could
+# do various other workarounds.
+#
+# background, this relies on how ps converts newlines in arguments to spaces, and
+# assumes we won't be searching for a command with spaces in its arguments
+rinr() {
+ # shellcheck disable=SC2009 # pgrep has no fixed string option, plus see above.
+ if ps h -o args -C "${1##*/}" | grep -Fxqv "$*" &>/dev/null || [[ $? == 141 ]]; then
+ "$@"
+ fi
+}
+# variation of above: run or wait if running
+rowir() {
+ local pid
+ pid=$(ps h -o 'pid,args' -C "${1##*/}" | sed -r 's/^[[:space:]]*([0-9]+)[[:space:]](.*)/\1\n\2/' | grep -B1 -Fx "$*" | head -n1 ||: )
+ if [[ $pid ]]; then
+ # https://unix.stackexchange.com/questions/427115/listen-for-exit-of-process-given-pid
+ tail --pid="$pid" -f /dev/null
+ else
+ "$@"
+ fi
+}
+
+mpvrpc-loadfile() {
+ local path nextpath cachedir finalpath nextpath count
+ cachedir=$HOME/.iank-music-cache
+ path="$1"
+ nextpath="$2"
+
+ # note: logic duplicated in beetpull
+ local remote_p=true
+ if [[ $HOSTNAME == kd ]]; then
+ remote_p=false
+ fi
+
+ if $remote_p; then
+ finalpath="$cachedir${path#/i/m}"
+ rowir rsync --partial -a --inplace --mkpath "b8.nz:$path" "$finalpath"
+ finalnextpath="$cachedir${nextpath#/i/m}"
+ count=$(pgrep -a -f "^rsync --partial -a --inplace --mkpath $cachedir" || [[ $? == 1 ]] )
+ # allow us to start 2 rsyncs in the background
+ if [[ $count == [01] ]]; then
+ rinr rsync --partial -a --inplace --mkpath "b8.nz:$nextpath" "$finalnextpath" &
+ fi
+ else
+ finalpath="$path"
+ fi
+ mpvrpc '{ "command": ["loadfile", "'"$finalpath"'"] }'
+}
+
# tag with beets.
# usage: beetag [-r] [-s] QUERY
# it lists the query, reads an input char for tagging one by one.
@@ -727,7 +840,8 @@ mpvrpc-percent-pos() {
# q quit
# ret next
#
-beetag() {
+# todo: enter should also unpause
+beetag() {
local last_genre_i fstring tag id char new_item char_i genre tag remove doplay i j random path
local do_rare_genres read_wait help line lsout tmp ls_line skip_lookback
local escape_char escaped_input expected_input skip_input_regex right_pad erasable_line seek_sec
@@ -766,7 +880,8 @@ beetag() {
fi
### end arg processing ###
- beetpull
+ # note: I used to do beetpull here, but mpv + ssfs on slowish
+ # connection leads to bad/buggy result.
do_rare_genres=false
volume=70
@@ -895,13 +1010,13 @@ beetag() {
first_play=false
for (( i=0; i<20; i++ )); do
if [[ $(mpvrpco '{ "command": ["get_property", "idle-active"] }' 2>/dev/null | jq .data) == true ]]; then
- mpvrpc '{ "command": ["loadfile", "'"$path"'"] }' 2>/dev/null
+ mpvrpc-loadfile "$path" 2>/dev/null
break
fi
sleep .1
done
else
- mpvrpc '{ "command": ["loadfile", "'"$path"'"] }'
+ mpvrpc-loadfile "$path"
fi
erasable_line=false
fi
@@ -939,7 +1054,7 @@ beetag() {
doplay=false
else
doplay=true
- mpvrpc '{ "command": ["loadfile", "'"$path"'"] }'
+ mpvrpc-loadfile "$path"
erasable_line=false
fi
beetag-nostatus 1
@@ -1646,7 +1761,7 @@ lipush() {
local p a
# excluding emacs for now
#p=(/a/opt/{emacs-debian11{,-nox},mu,emacs} /a/bin /a/exe /a/h /a/c /p/c/machine_specific/vps{,.hosts})
- p=(/a/bin /a/exe /a/h /a/c /p/c/machine_specific/vps{,.hosts} /c/roles/prom_export/files/simple/usr/local/bin/fsf-install-node-exporter)
+ p=(/a/bin /a/exe /a/h /a/c /p/c/machine_specific/vps{,.hosts} /c/roles/prom_export/files/simple/usr/local/bin/fsf-install-node-exporter /a/opt/fpaste)
a="-ahviSAXPH --specials --devices --delete --relative --exclude-from=/p/c/li-rsync-excludes"
ret=0
for h in li je bk; do
@@ -1677,19 +1792,13 @@ bindpush() {
dsign iankelling.org expertpathologyreview.com zroe.org amnimal.ninja
lipush
for h in li bk; do
- m sl $h.b8.nz <<'EOF'
-source ~/.bashrc
-m dnsup
-EOF
+ m ssh $h.b8.nz dnsup
done
}
bindpushb8() {
lipush
for h in li bk; do
- m sl $h <<'EOF'
-source ~/.bashrc
-m dnsb8
-EOF
+ m ssh $h.b8.nz dnsb8
done
}
@@ -1700,8 +1809,18 @@ dnsup() {
dnsb8() {
local f=/var/lib/bind/db.b8.nz
m ser stop named
- m sleep 1
- m sudo rm -fv $f.jnl $f.signed.jnl
+ # jbk is like a temp file. dunno if removing it helps
+
+ i=0
+ while pgrep '^named$' &>/dev/null; do
+ sleep .5
+ i=$(( i + 1 ))
+ if (( i > 100 )); then
+ echo "dnsb8: error: timeout waiting for named to exit"
+ return 1
+ fi
+ done
+ m sudo rm -fv $f.jnl $f.signed.jnl $f.jbk
m sudo install -m 644 -o bind -g bind /p/c/machine_specific/vps/bind-initial/db.b8.nz $f
m ser restart named
}
@@ -1785,6 +1904,74 @@ satoshi() { # $1 satoshi in usd
printf "$%.2f\n" "$(echo "scale=10; $price * $1"| bc -l)"
fi
}
+
+# Bitcoin holds open the wallet file. this causes problems for a
+# secondary computer running bitcoin and receiving a backup (as of
+# 2023). However, in 2024-02, I ran a backup where a receiving machine
+# had the wallet enabled and there was no error, so I don't know if this
+# is still an issue or likely it is an inconsistent behavior.
+#
+# As a workaround, this function is for enabling the wallet when I want
+# to use it and leave it disabled otherwise.
+walleton() {
+ local active
+ active=false
+ no_on=true
+ if [[ ! $(readlink -f /var/lib/bitcoind/wallets) == /q/wallets ]]; then
+ if systemctl --quiet is-active bitcoind; then
+ if [[ -e /tmp/no-bitcoinon ]]; then
+ no_on=true
+ else
+ if [[ $EUID == 0 ]]; then
+ m install -T -o iank -g iank /dev/null /tmp/no-bitcoinon
+ else
+ m touch /tmp/no-bitcoinon
+ fi
+ fi
+ active=true
+ m ser stop bitcoind
+ fi
+ m s ln -s /q/wallets /var/lib/bitcoind
+ sudo chown -h bitcoin:bitcoin /var/lib/bitcoind/wallets
+ if $active; then
+ m ser start bitcoind
+ if ! $no_on; then
+ m rm /tmp/no-bitcoinon
+ fi
+ fi
+ fi
+}
+walletoff() {
+ local active
+ active=false
+ no_on=true
+ if [[ $(readlink -f /var/lib/bitcoind/wallets) == /q/wallets ]]; then
+ if systemctl --quiet is-active bitcoind; then
+ if [[ -e /tmp/no-bitcoinon ]]; then
+ no_on=true
+ else
+ if [[ $EUID == 0 ]]; then
+ m install -T -o iank -g iank /dev/null /tmp/no-bitcoinon
+ else
+ m touch /tmp/no-bitcoinon
+ fi
+ fi
+ active=true
+ m ser stop bitcoind
+ else
+ echo note: bitcoind not active
+ fi
+ m rm /var/lib/bitcoind/wallets
+ if $active; then
+ # note, starting bitcoin always fails, but it actually
+ # succeeds. But this is strangely not consistent.
+ m ser start bitcoind
+ if ! $no_on; then
+ m rm /tmp/no-bitcoinon
+ fi
+ fi
+ fi
+}
#### end bitcoin related things
@@ -1810,6 +1997,71 @@ capache()
fi
}
+
+
+apache-header() {
+ # First paragraph is to avoid people being confused about why a
+ # file is apache licensed.
+ cat <<'EOF'
+# 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.
+
+EOF
+
+}
+
+# apply apache to git tracked bash files + README, except files with A?GPL3 header.
+apache-apply-repo() {
+ for f in $(git ls-files); do
+ [[ -L $f || ! -f $f ]] && continue
+ if [[ $f != README ]]; then
+ if ! grep -n '^#!/bin/bash' $f | grep ^1: &>/dev/null; then continue; fi
+ if head -n 10 $f | grep 'it under the terms of the GNU General Public License as published by' &>/dev/null; then continue; fi
+ fi
+ apache-apply $f
+ done
+}
+
+apache-apply() {
+ for file; do
+ if head -n1 "$file"| grep -E '^#!/bin/bash\b' &>/dev/null; then
+ {
+ head -n1 "$file"
+ apache-header
+ tail -n+2 "$file"
+ } | sponge "$file"
+ else
+ {
+ apache-header
+ cat "$file"
+ } | sponge "$file"
+ fi
+ done
+}
+# strip out the apache license from a file.
+apache-strip() {
+ # shellcheck disable=SC2044 # meh
+ for f in $(find . -type f -maxdepth 1); do if head -n1 "$f"| grep -E '^#!/bin/bash\b' &>/dev/null; then { head -n 20 $f | tac | sed '/^# limitations under the License.$/,/^# Copyright.*Ian Kelling$/d' | tac; tail -n+21 $f; } |sponge $f; fi ; done
+}
+
chrome() {
if type -p chromium &>/dev/null; then
cmd=chromium
@@ -1858,10 +2110,6 @@ digme() {
digdiff @ns{1,2}.iankelling.org "$@"
}
-tsr() { # ts run
- "$@" |& ts || return $?
-}
-
dup() {
local ran_d
ran_d=false
@@ -2169,7 +2417,9 @@ hstatus() {
done
}
-# work log
+## work log
+#
+# note: database location is specified in ~/.timetrap.yml, currently /p/.timetrap.db
wlog() {
local day i days_back
days_back=${1:-16}
@@ -2191,6 +2441,8 @@ tl() {
t s w
}
+
+# help me focus. opens 2 windows.
focus() {
/p/c/proc/focus/linux-amd64/focus &
watcharb5
@@ -2198,12 +2450,17 @@ focus() {
}
+# Display a list of the active window title
+# i've been on with 10 second samples going back
+# 5 minutes. If I've been on one window for 10 seconds
+# or longer, then display the second count.
+#
+# Press any key to exit.
watcharb5() {
local char ret
- killall arbtt-capture ||:
+ killall arbtt-capture &>/dev/null ||:
rm -f ~/.arbtt/capture.log
arbtt-capture --sample-rate=10 &
- clear
while true; do
arb5
ret=0
@@ -2220,30 +2477,49 @@ watcharb5() {
killall arbtt-capture ||:
return 0
fi
- clear
done
}
arb5() {
- local i l sec
- i=0
+ local i j l sec blanks line
+ local -a arbtt_lines
if [[ ! -e ~/.arbtt/capture.log ]]; then
sleep 5
fi
- # https://stackoverflow.com/questions/56486272/how-to-concat-multiple-fields-to-same-line-with-jq
- arbtt-dump -l 30 -t json | jq -r '.[] | [ ( .inactive / 1000 | floor ) , ( .windows[] | select (.active == true) |.title) ] | @tsv' \
- | tac | while read -r sec l; do
- if (( i % 6 == 0 && i >= 2 )); then
- echo "## $(( i / 6 + 1 )) ##"
- fi
- if (( sec > 10 )); then
- printf "%3d %s\n" $sec "$l"
- else
- printf " %s\n" "$l"
- fi
- i=$(( i + 1 ))
+ blanks=$(( LINES - 34 ))
+ for (( i=0; i < blanks; i++ )); do
+ echo
done
+
+ {
+ i=0
+ j=0
+ # https://stackoverflow.com/questions/56486272/how-to-concat-multiple-fields-to-same-line-with-jq
+ arbtt_lines=$(arbtt-dump -l 30 -t json | \
+ jq -r '.[] | [ ( .inactive / 1000 | floor ) , ( .windows[] | select (.active == true) |.title) ] | @tsv' | tac)
+ for line in "${arbtt_lines[@]}"; do
+ read -r sec l <<<"$line"
+ if (( j >= LINES )); then
+ break
+ fi
+ if (( i % 6 == 0 && i >= 2 )); then
+ j=$(( j + 1 ))
+ echo "## $(( i / 6 + 1 )) ##"
+ fi
+ if (( sec > 10 )); then
+ printf "%3d %s\n" $sec "$l" | sed -r "s/^(.{$COLUMNS}).*/\1/"
+ else
+ printf " %s\n" "$l" | sed -r "s/^(.{$COLUMNS}).*/\1/"
+ fi
+ i=$(( i + 1 ))
+ j=$(( j + 1 ))
+ done
+ while (( j < 34 && j < LINES )); do
+ echo
+ j=$(( j + 1 ))
+ done
+ } | tac
}
arbttlog() {
@@ -2290,7 +2566,10 @@ ilog-local() {
cd $d$n/"$chan"
hr
for x in *; do
- echo $x; sed "s/^./${x%log}/" $x; hr;
+ # *** are parts and joins and such, and they make reading hard.
+ # I probably will want to see them sometimes, just have to
+ # remove that part.
+ echo $x; sed "s/^./${x%log}/;/\*\*\*/d" $x; hr;
done
done
}
@@ -2353,18 +2632,62 @@ wgkey() {
umask $umask_orig
}
-declare -A vpn_ips
-vpn_ips[kd]=2
-# note: 1, 4, 5 are occupied by mail wireguard
-vpn_ips[x3]=8
-vpn_ips[sy]=12
-vpn_ips[x2]=13
-vpn_ips[kw]=27
-vpn_ips[bo]=28
-vpn_ips[frodo]=34
+host-info-all() {
+ host-info-update
+ bindpushb8
+ wrt-setup
+}
+
+
+# if you change a host's ip, then run
+# bindpushb8
+# wrt-setup
+host-info-update() {
+
+ local -A vpn_ips host_ips host_macs nonvpn_ips
+ local -a root_hosts nonroot_hosts
+
+ # the hosts with no mac
+ root_hosts=( bk je li b8.nz )
+ for h in ${root_hosts[@]}; do
+ root_hosts+=(${h}ex)
+ done
+ root_hosts+=(cmc)
+
+ while read -r ip host mac opts; do
+ if [[ $ip == *#* || ! $host ]]; then continue; fi
+ if [[ $opts == vpn ]]; then
+ vpn_ips[$host]=$ip
+ else
+ nonvpn_ips[$host]=$ip
+ fi
+
+
+ if [[ $opts == user=root ]]; then
+ # note: the b8.nz suffix is for the User part, the IdentityFile
+ # part is redundant to *.b8.nz.
+ root_hosts+=($host i$host $host.b8.nz i$host.b8.nz)
+ else
+ nonroot_hosts+=($host i$host)
+ fi
+
+ host_ips[$host]=$ip
+ host_macs[$host]=$mac
+ done
/dev/null; then
+ m sudo mount --bind /root/mount_namespaces /root/mount_namespaces
+ fi
+ m sudo mount --make-private /root/mount_namespaces
+ if [[ ! -e /root/mount_namespaces/$ns ]]; then
+ m sudo touch /root/mount_namespaces/$ns
+ fi
+ if ! sudo mountpoint /root/mount_namespaces/$ns >/dev/null; then
+ m sudo unshare --propagation slave --mount=/root/mount_namespaces/$ns /bin/true
+ fi
+
+ pid=$(servicepid $unit)
+ tmpf=$(mktemp --tmpdir $unit.XXXXXXXXXX)
+ export -p >$tmpf
+ printf "%s " "${@@Q}" >>$tmpf
+ echo >>$tmpf
+
+ m sudo nsenter -t $pid -n --mount=/root/mount_namespaces/$ns sudo -u $USER -i bash -c ". $tmpf & sleep 1; rm $tmpf"
+}
+
+
mnsr() { # mns run
local ns=$1
shift
mns $ns sudo -u iank -E env "PATH=$PATH" "$@"
}
+mnsnonetr() {
+ ns=$1
+ lomh
+ if ! s ip netns list | grep -Fx nonet &>/dev/null; then
+ s ip netns add nonet
+ fi
+ mns $ns --net=/var/run/netns/nonet /bin/bash
+ lomh
+}
+
mnsnonet() {
ns=$1
lomh
@@ -2637,7 +3009,7 @@ mdenable() {
two=false
case $1 in
- -2) two=true shift ;;
+ -2) two=true; shift ;;
esac
for md; do
@@ -2718,6 +3090,9 @@ mpvgpu() {
mpvd() {
mpv --profile=d "$@";
}
+mpva() {
+ mpv --profile=a "$@";
+}
# mpv all media files in . or $1
mpvm() {
local -a extensions arg
@@ -2840,6 +3215,34 @@ myprof() {
popd
}
+
+# Tail all recent prof logs. Copying from profanity has unwanted line breaks
+# especially for links.
+profr() {
+ case $HOSTNAME in
+ kd)
+ profr-local
+ ;;
+ *)
+ ssh b8.nz profr-local
+ ;;
+ esac
+}
+
+profr-local() {
+ local d0 d1
+ local -a files
+ d0="$(date +%Y_%m_%d).log"
+ d1="$(date -d '1 day ago' +%Y_%m_%d).log"
+ ngset
+ files=(/d/p/profanity/chatlogs/iank_at_fsf.org/{*,rooms/*}/{$d0,$d1})
+ ngreset
+ if (( ${#files[@]} > 0 )); then
+ cat "${files[@]}" | sort | tail -n 40
+ fi
+}
+
+
# Tail pms in the last day, for the case where we restart profanity and
# didn't check for pms beforehand. Assume the most recent logs are on kd.
# If that isn't the case, use prof-recent-local
@@ -2853,7 +3256,6 @@ prof-recent() {
;;
esac
}
-
prof-recent-local() {
local d dates date files f
# consider making the day count passed by parameter. note: this works: $(date -d '2 day ago' +%Y_%m_%d)
@@ -2873,6 +3275,35 @@ prof-recent-local() {
done
}
+prof-sort() {
+ case $HOSTNAME in
+ kd)
+ prof-recent-sort
+ ;;
+ *)
+ ssh b8.nz prof-recent-sort
+ ;;
+ esac
+}
+
+prof-recent-sort() {
+ local d dates date files f
+ # consider making the day count passed by parameter. note: this works: $(date -d '2 day ago' +%Y_%m_%d)
+ dates=("$(date +%Y_%m_%d)" "$(date -d '1 day ago' +%Y_%m_%d)" )
+ files=()
+ for d in /d/p/profanity/chatlogs/iank_at_fsf.org/!(rooms); do
+ for date in ${dates[@]}; do
+ f=$d/$date.log
+ if [[ -e $f ]]; then
+ files+=($f)
+ fi
+ done
+ done
+ for f in "${files[@]}"; do
+ sed "s/\$/ $f/" $f
+ done | sort
+}
+
# usage: debvm DEBIAN_VERSION RAM_MB
debvm() {
@@ -2965,11 +3396,12 @@ ngo() {
otp() {
oathtool --totp -b "$*" | xclip -selection clipboard
}
+# run cmd and copy output
j() {
"$@" |& pee "xclip -r -selection clipboard" cat
}
-# x copy
+# xorg copy. copy text piped into command
xc() {
xclip -r -selection clipboard
}
@@ -3140,16 +3572,11 @@ spd() {
}
spamf() { # spamtest on FILE
- local spamcpre spamdpid
-
if (( $# != 1 )); then
e spamtest error: expected 1 arg, filename >&2
return 1
fi
-
- spamdpid=$(systemctl status spamassassin| sed -n '/^ *Main PID:/s/[^0-9]//gp')
- spamcpre="nsenter -t $spamdpid -n -m"
- s $spamcpre sudo -u Debian-exim spamassassin -t --cf='score PYZOR_CHECK 0' <"$1"
+ sdncmdroot spamassassin sudo -u Debian-exim spamassassin -t --cf='score PYZOR_CHECK 0' <"$1"
}
@@ -3393,16 +3820,16 @@ tu() {
$s /a/exe/teeu "$@"
}
+# execute exim in its namespace. Useful args like -Mrm
enn() {
local ecmd pid
ecmd="/usr/sbin/exim4 -C /etc/exim4/my.conf"
if ip a show veth1-mail &>/dev/null; then
s $ecmd "$@"
- return
+ else
+ sdncmdroot exim4 $ecmd "$@"
fi
- pid=$(pgrep -f "/usr/sbin/exim4 -bd -q10m -C /etc/exim4/my.conf"|h1)
- m s nsenter -t $pid -n -m $ecmd "$@"
}
# get pid of systemd service
@@ -3444,7 +3871,7 @@ sdnbash() { # systemd namespace bash
m sudo nsenter -t $pid -n -m sudo -u $USER -i bash
}
-sdnbashroot() { # systemd namespace bash
+sdnbashroot() { # systemd namespace bash as root
local unit pid
if (( $# != 1 )); then
echo $0: error wrong number of args >&2
@@ -3456,16 +3883,34 @@ sdnbashroot() { # systemd namespace bash
}
-sdncmd() { # systemd namespace cmd
+# systemd namespace cmd
+# usage: UNIT CMD...
+sdncmd() {
+ local unit pid tmpf
+ if (( $# <= 1 )); then
+ echo $0: error wrong number of args >&2
+ return 1
+ fi
+ unit=$1
+ shift
+ pid=$(servicepid $unit)
+ tmpf=$(mktemp --tmpdir $unit.XXXXXXXXXX)
+ export -p >$tmpf
+ printf "%s " "${@@Q}" >>$tmpf
+ echo >>$tmpf
+ m sudo nsenter -t $pid -n -m sudo -u $USER -i bash -c ". $tmpf & rm $tmpf"
+}
+
+sdncmdroot() { # systemd namespace root command
local unit pid
- if (( $# <= 2 )); then
+ if (( $# < 2 )); then
echo $0: error wrong number of args >&2
return 1
fi
unit=$1
shift
pid=$(servicepid $unit)
- m sudo nsenter -t $pid -n -m sudo -u $USER -i "$@"
+ m sudo nsenter -t $pid -n -m "$@"
}
@@ -3479,13 +3924,7 @@ mailnnbash() {
# }
eximbash() {
- local pid
- pid=$(pgrep -f "/usr/sbin/exim4 -bd -q10m -C /etc/exim4/my.conf"|h1)
- if [[ ! $pid ]]; then
- echo "eximbash: failed to find exim pid. systemctl -n 30 status exim4:"
- systemctl status exim4
- fi
- m sudo nsenter -t $pid -n -m
+ sdnbashroot exim4
}
spamnn() {
local spamdpid
@@ -3493,7 +3932,7 @@ spamnn() {
m sudo nsenter -t $spamdpid -n -m sudo -u Debian-exim spamassassin "$@"
}
unboundbash() {
- m sudo nsenter -t "$(systemctl status unbound| sed -n '/^ *Main PID:/s/[^0-9]//gp')" -n -m sudo -u $USER -i bash
+ sdnbashroot unbound
}
nmtc() {
@@ -3527,14 +3966,13 @@ mailnncheck() {
vpncmd() {
- m sudo -E env "PATH=$PATH" nsenter -t "$(pgrep -f "/usr/sbin/openvpn .* --config /etc/openvpn/.*client.conf")" -n "$@"
+ sdncmd openvpn-client-tr@client.service "$@"
}
-
vpni() {
- vpncmd sudo -u iank env "PATH=$PATH" "$@"
+ sdncmd openvpn-client-tr@client.service bash
}
vpnbash() {
- vpncmd bash
+ sdncmdroot openvpn-client-tr@client.service bash
}
@@ -3570,11 +4008,31 @@ fixu() {
# unmute
um() {
- pactl set-sink-mute @DEFAULT_SINK@ false
+ local sink card
+ sink=$(pactl get-default-sink)
+ if [[ $sink == auto_null ]]; then
+ # guessing there is just one with an off profile. otherwise we will
+ # need some other solution, like storing the card identifier that we
+ # muted with nap.
+ card=$(pacmd list-cards | sed -n '/^[[:space:]]*index:/{s/^[[:space:]]*index://;h};/^[[:space:]]*active profile: $/{g;p;q}')
+ m pacmd set-card-profile "$card" output:analog-stereo
+ fi
+
+ m pactl set-sink-mute @DEFAULT_SINK@ false
rm -f /tmp/ianknap
}
+
nap() {
- pactl set-sink-mute @DEFAULT_SINK@ true
+ local sink card
+ sink=$(pactl get-default-sink)
+ card="${sink%.*}"
+ card="${card/output/card}"
+ m pacmd set-card-profile "$card" off
+
+ # clicking on a link in a browser can cause unmute.
+ # I don't want that. So, use a stronger form of mute
+ # than this.
+ #pactl set-sink-mute @DEFAULT_SINK@ true
touch /tmp/ianknap
}
@@ -3666,7 +4124,13 @@ vpnoffc() { # vpn off client
ser stop openvpn-client-tr@client
}
vpnc() {
- ser start openvpn-client-tr@client
+ local unit
+ unit=openvpn-client-tr@client
+ sudo -v
+ if [[ $(systemctl is-active $unit) != active ]]; then
+ s systemctl start $unit
+ sleep 1
+ fi
}
@@ -3711,12 +4175,6 @@ vrun() {
"$@"
}
-f=/a/f/ansible-configs/files/common/etc/fsf-workstation-bashrc.sh
-if [[ -e $f ]]; then
- # shellcheck disable=SC1090
- source $f
-fi
-
electrum() {
# https://electrum.readthedocs.io/en/latest/tor.html
# https://github.com/spesmilo/electrum-docs/issues/129
@@ -3728,6 +4186,12 @@ monero() {
}
+# grep + find
+gef() {
+ faf | grep -E "$@" ||:
+ rgv "$@"
+}
+
# rg my main files
rgm() {
rg "$@" /p/w.org /a/t.org /a/work.org /b
@@ -3740,15 +4204,42 @@ rem() {
find $paths -not \( -name .svn -prune -o -name .git -prune \
-o -name .hg -prune -o -name .editor-backups -prune \
-o -name .undo-tree-history -prune \) 2>/dev/null | grep -iP --color=auto -- "$*" ||:
- rgv -- "$*" $paths /a/t.org /p/w.org /a/work.org ||:
+ rgv $local_rgv_args -g "!bash_unpublished" -- "$*" $paths /a/work.org ||:
+}
+reml() { # rem with limit to 5 matches per file
+ local_rgv_args="-m 5"
+ rem "$@"
}
-reml() { # with limit to 5 matches per file
+
+rep() {
local paths
- paths="/p/c /b"
+ paths="/p/c"
find $paths -not \( -name .svn -prune -o -name .git -prune \
-o -name .hg -prune -o -name .editor-backups -prune \
-o -name .undo-tree-history -prune \) 2>/dev/null | grep -iP --color=auto -- "$*" ||:
- rgv -m 5 -- "$*" $paths /a/t.org /p/w.org /a/work.org ||:
+ rgv $local_rgv_args -- "$*" $paths /a/t.org /p/w.org ||:
+}
+repl() { # rem with limit to 5 matches per file
+ local local_rgv_args="-m 5"
+ rem "$@"
+}
+
+
+# re on common fsf files
+ref() {
+ local paths
+ paths="/f/gluestick /f/brains /f/s /c"
+ find $paths -not \( -name .svn -prune -o -name .git -prune \
+ -o -name .hg -prune -o -name .editor-backups -prune \
+ -o -name .undo-tree-history -prune \) 2>/dev/null | grep -iP --color=auto -- "$*" ||:
+ rgv -- "$*" $paths /a/work.org ||:
+}
+
+
+# for use in /f/bind
+fupzone() {
+ # shellcheck disable=SC2046 # i want word splitting
+ ./update-zone $(i s | sed -rn 's/.*db\.(.*)/\1/p')
}
# setup:
@@ -3880,9 +4371,6 @@ mypyenvinit () {
}
-export GOPATH=$HOME/go
-path-add $GOPATH/bin
-path-add /usr/local/go/bin
# I have the git repo and a release. either one should work.
# I have both because I was trying to solve an issue that
@@ -3914,12 +4402,18 @@ fi
# rg with respecting vcs ignore files
rgv() {
ret=0
+ # settings that are turned off for pipes, keep them on.
+ # Found by searching for "terminal" in --help
+ # --heading
+ # -n
+ #
# -. = search dotfiles
# -z = search zipped files
# -i = case insensitive
# -M = max columns
# --no-messages because of annoying errors on broken symlinks
- command rg -. -z --no-messages -i -M 900 -g '!.git' -g '!auto-save-list' -g '!.savehist' "$@" || ret=$?
+ # --no-ignore-parent because i have /a/.git which ignores almost everything under it.
+ command rg -n --heading -. -z --no-messages -i -M 900 --no-ignore-parent -g '!.git' -g '!auto-save-list' -g '!.savehist' "$@" || ret=$?
return $ret
}
@@ -3986,7 +4480,7 @@ hssh-update() {
case $HOSTNAME in
sy|kd)
hosts=(
- kd x3.office.fsf.org syw
+ kd.b8.nz x3.office.fsf.org syw x2.b8.nz
)
;;
x3)
@@ -4007,6 +4501,84 @@ hssh-update() {
fi
}
+noi3bar() {
+ touch /tmp/noi3bar
+}
+i3bar() {
+ rm -fv /tmp/noi3bar
+}
+
+# example:
+# <#part type="image/jpeg" filename="/home/iank/2023-12-24-ski-trip.jpg" disposition=attachment> <#/part>
+#
+attach-txt() {
+ local f
+ for f; do
+ if [[ ! -s $f ]]; then
+ e "error: empty or non-existent file $f"
+ return 1
+ fi
+ done
+ for f; do
+ echo '<#part type="image/jpeg" filename="'"$(rl "$f")"'" disposition=attachment> <#/part>'
+ done | ec
+}
+
+ctof() {
+ units "tempC($1)" tempF
+}
+
+ftoc() {
+ units "tempF($1)" tempC
+}
+
+# requires dns/firewall setup first
+local-icecast() {
+ web-conf -e ian@iankelling.org -f 8000 - apache2 live.iankelling.org <<'EOF'
+
+AuthType Basic
+AuthName "basic_auth"
+# created with
+# htpasswd -c icecast-fsf-htpasswd USERNAME
+AuthUserFile "/etc/icecast-fsf-htpasswd"
+Require valid-user
+
+
+AuthType Basic
+AuthName "basic_auth"
+AuthUserFile "/etc/icecast-fsf-tech-htpasswd"
+Require valid-user
+
+EOF
+}
+
+# obs screen switching of
+obof() {
+ ls -l /tmp/no-obs-auto-scene-switch
+ touch /tmp/no-obs-auto-scene-switch
+}
+# obs screen switching on
+obon() {
+ ls -l /tmp/no-obs-auto-scene-switch
+ if [[ -e /tmp/no-obs-auto-scene-switch ]]; then
+ rm -f /tmp/no-obs-auto-scene-switch
+ fi
+}
+
+obs-gen-profiles() {
+ local p=/p/c/basic/profiles
+ sed 's/fsf-sysops/fsf-tech/g' $p/fsfsysops/basic.ini >$p/fsftech/basic.ini
+ sed 's/fsf-sysops/fsf/g' $p/fsfsysops/basic.ini >$p/fsf/basic.ini
+}
+
+# terminal clear. like clear, but put the prompt at the bottom,
+# useful for obs streaming the bottom half of a terminal window.
+tclear() {
+ for ((i=0; i