# * functions
+
+
multimic() {
local i
local -a sources
ssh bow rm /tmp/oegu.jpg
feh /t/oegu.jpg
}
+zmon() {
+ while true; do
+ ziva-screen
+ sleep 15
+ done
+}
slemacs() {
local arg rtime v
# sshfs example:
# s sshfs bu@$host:/bu/home/md /bu/mnt -o reconnect,ServerAliveInterval=20,ServerAliveCountMax=30 -o allow_other
+edelayoff() {
+ echo all >/etc/exim4/no-delay-eximids
+}
+edelayon() {
+ echo >/etc/exim4/no-delay-eximids
+}
+
eqgo() {
- local -a array tmpstr
+ local -a array tmpstr delayon
+ delayon=true
+ if grep -qFx all /etc/exim4/no-delay-eximids; then
+ delayon=false
+ fi
+ if $delayon; then
+ echo all >/etc/exim4/no-delay-eximids
+ fi
tmpstr=$(exiqgrep -i -r.\*)
mapfile -t array <<<"$tmpstr"
enn -M "${array[@]}"
+ if $delayon; then
+ echo >/etc/exim4/no-delay-eximids
+ fi
}
eqgo1() {
- enn -M "$(exipick -i -r.\*|h1)"
+ local eid
+ eid="$(exipick -i -r.\*|h1)"
+ sed -n "/^all$/p;\$a $eid" /etc/exim4/no-delay-eximids
+ enn -M "$eid"
+}
+ennm() {
+ local eid
+ for eid; do
+ printf "%s\n" "$eid" >>/etc/exim4/no-delay-eximids
+ done
+ enn -M "$@"
}
schroot -c buster -- anki
}
+daycat() {
+ ngset
+ hrcat /m/md/daylert/{cur,new}/*
+ ngreset
+}
+dayclear() {
+ ngset
+ rm -f /m/md/daylert/{cur,new}/*
+}
+
+
acat() {
ngset
hrcat /m/md/alerts/{cur,new}/*
/a/opt/android-studio/bin/studio.sh "$@" & r
}
-# convert brains path to url
-# /f/brains/sysadmin/interns/2022/nick_shrader/intro_blog_post.mdwn
-# becomes
-# https://brains.fsf.org/wiki/sysadmin/interns/2022/nick_shrader/intro_blog_post
-iki() {
- local url path input
+# Convert brains file path to url and vice versa
+# usage: brains [URL_OR_PATH]
+brains() {
+ _iki-convert '(/a)?/f/brains' brains.fsf.org/wiki "$@"
+}
+glue() {
+ _iki-convert '(/a)?/f/gluestick' gluestick.office.fsf.org "$@"
+}
+
+# usage: $0 REPO_PATH [URL_OR_PATH]
+_iki-convert() {
+ local url prefix path input err repo_dir dir url_dir url
+ repo_dir="$1"
+ prefix="$2"
+ shift 2
+ err=false
+ if $err; then
+ return 1
+ fi
if [[ $1 ]]; then
input="$*"
else
- read -r -p "enter path or url" input
+ read -r -p "enter path or url"$'\n' input
fi
case $input in
http*)
- path="/f/brains/${input##https://brains.fsf.org/wiki/}"
+ path="$repo_dir/${input##http*://"$prefix"/}"
if [[ $path == */ ]]; then
path=${path%/}.mdwn
- fi
+ fi
j printf "%s\n" "$path"
;;
*)
- url=$(readlink -f "$input")
- url="https://brains.fsf.org/wiki/${url#*brains/}"
+ path=$(fp "$input")
+ url_dir=$(echo "$path" | sed -r "s,^$repo_dir/,,")
+ url="https://$prefix/$url_dir"
url="${url%.mdwn}/"
j echo "$url"
;;
esac
-
}
+
# Generate beet smartplaylists for navidrome.
# for going in the reverse direction, run
# /b/ds/navidrome-playlist-export
# beet playlist. use beetag with a playlist name
bpl() {
local playlist playlist_regex
+ case $1 in
+ -h|--help)
+ for playlist in "${!bpla[@]}"; do
+ printf "%s\n" "$playlist"
+ done
+ return 0
+ ;;
+ esac
+
playlist="${*: -1}"
playlist_regex='[a-z0-9_]'
if [[ ! $playlist =~ $playlist_regex ]]; then
cat <<'EOF'
-y other genres z fg player ' = toggle play 1-5 rate
+y other genres z fg player ' = toggle play 1-5 rate ] repeat1
; previous _ = delete up/down skip mpv vol,pause,seek
EOF
hr
fi
if $erasable_line; then
# https://stackoverflow.com/a/71286261
+ # erase line / delete line in terminal
printf '\033[1A\033[K'
fi
erasable_line=false
# 1-5 rate
# q quit
# ret next
+#
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
local pl_state_path pl_state_dir pl_state_file tmpstr
- local new_random pl_seed_path seed_num seed_file fmt first_play
- local -a pl_tags buttons button_map ids tags tmp_tags initial_ls ls_lines paths
+ local new_random pl_seed_path seed_num seed_file fmt first_play repeat1
+ local -a buttons button_map ids tags tmp_tags initial_ls ls_lines paths
local -A button_i
local -i i j volume scrolled id_count line_int skip_start pre_j_count head_count skip_lookback
local -i overflow_lines overflow
scrolled=999 # more than any $LINES
### begin arg processing ###
random=false
+ repeat1=false
new_random=false
case $1 in
-r)
fi
pl_state_dir=/i/info/pl-state
if [[ $playlist ]]; then
- pl_state_dir=$pl_state_dir/nopl
- else
pl_state_dir=$pl_state_dir/$playlist
+ else
+ pl_state_dir=$pl_state_dir/nopl
fi
pl_state_path=$pl_state_dir/$pl_state_file
pl_seed_path=$pl_state_dir/$seed_file
{ base64 < /dev/urandom | head -c 200 ||:; echo; } > $pl_seed_path
fi
-
-
# PijokVipiotOzeph is just a random string for a delimiter
+ # shellcheck disable=SC2016 # false positive
fmt='%ifdef{rating,$rating }'"$fstring"'$genre | $title - $artist - $album $length $id PijokVipiotOzeph $path'
# shellcheck disable=SC2016 # obvious reason
tmpstr=$(beet ls -f "$fmt" "$@" | { if $random; then sort -R --random-source=$pl_seed_path; else cat; fi; } )
mapfile -t initial_ls <<<"$tmpstr"
+ if [[ ! ${initial_ls[0]} ]]; then
+ echo "beetag: error: no result from beet ls $*"
+ return 1
+ fi
id_count=${#initial_ls[@]}
for line in "${initial_ls[@]}"; do
path="${line#*PijokVipiotOzeph }"
echo volume=$volume
continue
;;
+ ']')
+ if $repeat1; then
+ repeat1=false
+ else
+ repeat1=true
+ fi
+ echo repeat1=$repeat1
+ continue
+ ;;
q)
kill-bg-quiet
return
fi
fi
done
- if (( j < id_count - 1 )); then
- j+=1
- else
- j=0
+ if ! $repeat1; then
+ if (( j < id_count - 1 )); then
+ j+=1
+ else
+ j=0
+ fi
fi
if [[ $playlist ]]; then
echo $j >$pl_state_path
# pull in beets library locally
beetpull() {
- local sshfs_host
+ local sshfs_host sshfs_cmd
sshfs_host=b8.nz
if [[ $HOSTNAME == kd ]]; then
return 0
s mkdir /i
s chown iank:iank /i
fi
- if ! mountpoint /i &>/dev/null; then
- m sshfs $sshfs_host:/i /i
+ sshfs_cmd="sshfs -o ServerAliveInterval=15,reconnect $sshfs_host:/i /i"
+ if ! pgrep -f "^$sshfs_cmd$" >/dev/null; then
+ m $sshfs_cmd
fi
}
rm $tmpf
}
+# prettify the date
+btrbk-date() {
+ local indate
+ indate="$1"
+ shift
+ date +%F_%T%:::z -d "$(sed -r 's/(.{4})(..)(.{5})(..)(.*)/\1-\2-\3:\4:\5/' <<<"$indate")" "$@"
+}
+btrbk-undate() {
+ # fudCaHougfirp is a random string
+ { if [[ $1 ]]; then
+ echo "$1"
+ else
+ cat
+ fi
+ } | sed -r 's/-0([45])( |$)/fudCaHougfirp0\100/;s/_/T/;s/[:-]//g;s/fudCaHougfirp/-/'
+
+}
+btrbk-date-sed() {
+ local line
+ while read -r line; do
+ if [[ $line == *20[0-9][0-9][0-9][0-9][0-9][0-9]T[0-9][0-9][0-9][0-9][0-9][0-9]-0[45]00* ]]; then
+ pre="${line%%20[0-9][0-9][0-9][0-9][0-9][0-9]T[0-9][0-9][0-9][0-9][0-9][0-9]-0[45]00*}"
+ post="${line##*20[0-9][0-9][0-9][0-9][0-9][0-9]T[0-9][0-9][0-9][0-9][0-9][0-9]-0[45]00}"
+ mid="${line:${#pre}:22}"
+ echo "$pre$(btrbk-date "$mid")$post"
+ else
+ echo "$line"
+ fi
+ done
+}
+jrbtrbk() {
+ jr -u btrbk-run -u btrbk -u switch-mail-host "$@"
+}
+
+# internal function
+btrbk-host-debug-show-host() {
+ for f; do
+ snaphost=
+ for host in $remote $alt local; do
+ if line=$(grep -P "\S*$f" /tmp/b/s/$host.log); then
+ if [[ $snaphost ]]; then
+ e error: snaphost=$snaphost, host=$host line="$line"
+ fi
+ if [[ $line == ssh* ]]; then
+ tmp="${line#ssh://}"
+ snaphost="${tmp%%/*}"
+ else
+ snaphost=$host
+ fi
+ fi
+ done
+ echo $snaphost $f | btrbk-date-sed
+ done
+}
+
+# If we get a btrfs receive error like this:
+# ERROR: ... clone: did not find source subvol
+# running this command will help track down the problem.
+# Alter remote= and alt=. When I used it, remote is
+# the host having the error when I push a snapshot.
+# Alt is just the other host that takes snapshots
+# besides the local host.
+btrbk-host-debug() {
+
+ remote=b8.nz
+ alt=sywg.b8.nz
+
+ mkdir -p /tmp/b/s
+ for host in $remote $alt; do
+ h=$(ssh $host hostname)
+ rsync -a /var/log/btrbk $host:/var/log/btrbk /var/log/btrbk/$h
+ grr '\bsnapshot success' /var/log/btrbk/$h >/tmp/b/$h.log
+
+ ## this takes a while, we only want to do it on 1st run
+ # if [[ -s /tmp/b/$host.log ]]; then continue; fi
+ # ssh $host journalctl -u btrbk-run -u btrbk -u switch-mail-host >/tmp/b/$host.log
+ done
+ gr '\bsnapshot success' /var/log/btrbk/*.log >/tmp/b/local.log
+ cd /tmp/b
+ for f in *.log; do
+ gr '\bsnapshot success' $f >s/$f
+ done
+ cd /mnt/root/btrbk
+ localq=(q.*)
+ declare -A localq_a
+ for f in "${localq[@]}"; do
+ localq_a[$f]=t
+ done
+
+ remoteq=()
+ for f in $(ssh $remote "cd /mnt/root/btrbk; echo q.*"); do
+ if [[ ! ${localq_a[$f]} ]]; then
+ remoteq+=($f)
+ fi
+ done
+ btrbk-host-debug-show-host "${localq[@]}"
+ if (( ${#remoteq[@]} >= 1 )); then
+ echo "=== $remote only ===="
+ btrbk-host-debug-show-host ${remoteq[@]}
+ fi
+
+}
+
# note, to check for glue records
# First, find some the .org nameservers:
# dig +trace iankelling.org
return 1
;;
esac
- # run latest
- install-my-scripts
# todo: consider changing this to srun and having the args come
# from a file like /etc/default/btrbk, like is done in exim
s jdo btrbk-run "$@"
if [[ ! $tmp ]]; then
s ssh-add /root/.ssh/home
fi
- install-my-scripts
s jdo switch-mail-host "$@"
return $ret
}
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})
+ 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
return $ret
}
bkpush() { # no emacs. for running faster.
- p=(/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)
a="-ahviSAXPH --specials --devices --delete --relative --exclude-from=/p/c/li-rsync-excludes"
ret=0
m rsync "$@" $a ${p[@]} /p/c/machine_specific/bk root@bk.b8.nz:/ || ret=$?
return $ret
}
jepush() { # no emacs. for running faster.
- p=(/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)
a="-ahviSAXPH --specials --devices --delete --relative --exclude-from=/p/c/li-rsync-excludes"
ret=0
m rsync "$@" $a ${p[@]} /p/c/machine_specific/je root@je.b8.nz:/ || ret=$?
dsign iankelling.org expertpathologyreview.com zroe.org amnimal.ninja
lipush
for h in li bk; do
- m sl $h <<'EOF'
+ m sl $h.b8.nz <<'EOF'
source ~/.bashrc
m dnsup
EOF
feh() {
# F = fullscren, z = random, Z = auto zoom
- command feh -FzZ "$@"
+ command feh --auto-rotate -FzZ "$@"
}
}
gse() {
- local email=ian@iankelling.org
+ local email=iank@fsf.org
git send-email --notes "--envelope-sender=<$email>" \
--suppress-cc=self "$@"
}
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}
- for (( i=0; i<days_back; i++ )); do
+ for (( i=days_back; i>=0; i-- )); do
day=$( date +%F -d @$((EPOCHSECONDS - 86400*i )) )
date "+%a %b %d" -d @$((EPOCHSECONDS - 86400*i )) | tr '\n' ' '
/a/opt/timetrap/bin/t d -ftotal -s $day -e $day all -m '^w|lunch$'
t s w
}
+
+# help me focus. opens 2 windows.
focus() {
/p/c/proc/focus/linux-amd64/focus &
watcharb5
}
+# 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
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() {
}
ilogs-local() {
- cd /var/lib/znc/moddata/log/iank/freenode/
- hr
- for x in "#$1/"*; do
- base=${x##*/}
- files=()
- for f in $@; do
- tmp=\#$f/$base
- if [[ -e $tmp ]]; then
- files+=(\#$f/$base)
- fi
- done
- sed \"s/^./${base%log}/\" ${files[@]}|sort -n
+ d=/var/lib/znc/moddata/log/iank/
+ for n in freenode libera; do
+ cd $d/$n
hr
+ for x in "#$1/"*; do
+ base=${x##*/}
+ files=()
+ for f in $@; do
+ tmp=\#$f/$base
+ if [[ -e $tmp ]]; then
+ files+=(\#$f/$base)
+ fi
+ done
+ sed \"s/^./${base%log}/\" ${files[@]}|sort -n
+ hr
+ done
done
}
ilogs() {
chan="$1"
d=/var/lib/znc/moddata/log/iank/
for n in freenode libera; do
- cd $d$n/"$chan" && hr
+ if [[ ! -d $d$n/"$chan" ]]; then
+ continue
+ fi
+ cd $d$n/"$chan"
+ hr
for x in *; do
echo $x; sed "s/^./${x%log}/" $x; hr;
done
# jr() { journalctl "$@" | jfilter | less ; }
# jrf() { journalctl -n 200 -f "$@" | jfilter; }
-jr() { journalctl "$@" ; }
-jrf() { journalctl -n 200 -f "$@" ; }
-
-
-ccomp journalctl jtail jr jrf
## old version for model01. i need to get that firmware working again.
# kff() { # keyboardio firmware flash. you must hold down the tilde key
wg genkey | tee $name-priv.key | wg pubkey > $name-pub.key
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
+
+vpn-ips-update() {
+ local host ipsuf f files
+ for host in ${!vpn_ips[@]}; do
+ ipsuf=${vpn_ips[$host]}
+ wghole $host $ipsuf
+ u /a/bin/ds/machine_specific/$host/filesystem/etc/systemd/system/openvpn-client-tr@.service <<EOF
+[Unit]
+Description=OpenVPN tunnel for %I
+After=syslog.target network-online.target
+Wants=network-online.target
+Documentation=man:openvpn(8)
+Documentation=https://community.openvpn.net/openvpn/wiki/Openvpn24ManPage
+Documentation=https://community.openvpn.net/openvpn/wiki/HOWTO
+Requires=iptables.service
+
+[Service]
+Type=notify
+RuntimeDirectory=openvpn-client
+RuntimeDirectoryMode=0710
+WorkingDirectory=/etc/openvpn/client
+ExecStart=/usr/sbin/openvpn --suppress-timestamps --nobind --config /etc/openvpn/client/%i.conf
+# todo, try reenabling this from the default openvpn,
+# it was disabled so we could do bind mounts as a command,
+# but now systemd handles it
+#CapabilityBoundingSet=CAP_IPC_LOCK CAP_NET_ADMIN CAP_NET_RAW CAP_SETGID CAP_SETUID CAP_SYS_CHROOT CAP_DAC_OVERRIDE
+LimitNPROC=10
+# DeviceAllow=/dev/null rw
+# DeviceAllow=/dev/net/tun rw
+
+# we use .1 to make this be on a different network than kd, so that we can
+# talk to transmission on kd from remote host, and still use this
+# vpn.
+ExecStartPre=/usr/bin/flock -w 20 /tmp/newns.flock /a/bin/newns/newns -n 10.174.$ipsuf start %i
+ExecStartPre=/sbin/iptables-restore /a/bin/distro-setup/transmission-firewall/netns.rules
+# allow wireguard network to connect
+ExecStartPre=/usr/sbin/ip r add 10.8.0.0/24 via 10.174.$ipsuf.1 dev veth1-client
+ExecStopPost=/usr/bin/flock -w 20 /tmp/newns.flock /a/bin/newns/newns stop %i
+PrivateNetwork=true
+BindReadOnlyPaths=/etc/tr-resolv:/run/systemd/resolve:norbind /etc/basic-nsswitch:/etc/resolved-nsswitch:norbind
+
+[Install]
+WantedBy=multi-user.target
+EOF
+ done
+
+ {
+ for host in ${!vpn_ips[@]}; do
+ ipsuf=${vpn_ips[$host]}
+ cat <<EOF
+local-data-ptr: "10.2.0.$ipsuf $host.b8.nz"
+EOF
+ done
+ } | u /b/ds/ptr-data
+
+ {
+ for host in ${!vpn_ips[@]}; do
+ ipsuf=${vpn_ips[$host]}
+ cat <<EOF
+$host A 10.2.0.$ipsuf
+${host}wg A 10.8.0.$ipsuf
+${host}vp A 10.5.5.$ipsuf
+${host}tr A 10.174.$ipsuf.2
+EOF
+ done
+ } | cedit vpn-ips-update /p/c/machine_specific/vps/bind-initial/db.b8.nz ||:
+
+
+ echo checking for stray files:
+
+ initial_dir=$PWD
+ cd /a/bin/ds/machine_specific
+ ngset
+ files=( */filesystem/etc/systemd/system/openvpn-client-tr@.service )
+ ngreset
+ cd $initial_dir
+ for f in "${files[@]}"; do
+ host=${f%%/*}
+ if [[ ! ${vpn_ips[$host]} ]]; then
+ e /a/bin/ds/machine_specific/$host/filesystem/etc/systemd/system/openvpn-client-tr@.service
+ fi
+ done
+
+ cd /p/c/machine_specific
+ ngset
+ files=( */filesystem/etc/wireguard/wghole.conf )
+ ngreset
+ cd $initial_dir
+ for f in "${files[@]}"; do
+ host=${f%%/*}
+ if [[ ! ${vpn_ips[$host]} ]]; then
+ e /p/c/machine_specific/$host/filesystem/etc/wireguard/wghole.conf
+ e cedit -s $host /p/c/machine_specific/li/filesystem/etc/wireguard/wgmail.conf '<<<""'
+ fi
+ done
+}
+
+# usage host ipsuf [extrahost]
+#
+# If the keys already exist and you want new ones, remove them:
+# rm /p/c/machine_specific/$host/filesystem/etc/wireguard/hole-{priv,pub}.key
+#
+# extrahost is a host/cidr that is allowed to go be routed through the
+# vpn by this host.
wghole() {
- if (( $# != 2 )); then
- e expected 2 arg of hostname, ip suffix >&2
+ if (( $# < 2 || $# > 3 )); then
+ e expected 2-3 arg of hostname, ip suffix, and extrahost >&2
return 1
fi
- local host ipsuf umask_orig
+ local host ipsuf umask_orig vpn_allowed
host=$1
ipsuf=$2
+ if [[ $3 ]]; then
+ extrahost=,$3
+ fi
+ for vpn_host in ${!vpn_ips[@]}; do
+ if [[ $vpn_host == "$host" ]]; then
+ continue
+ fi
+ vpn_allowed+=",10.174.${vpn_ips[$vpn_host]}.2/32"
+ done
mkdir -p /p/c/machine_specific/$host/filesystem/etc/wireguard
(
cd /p/c/machine_specific/$host/filesystem/etc/wireguard
umask_orig=$(umask)
umask 0077
- wg genkey | tee hole-priv.key | wg pubkey > hole-pub.key
+ if [[ ! -s hole-priv.key || ! -s hole-pub.key ]]; then
+ wg genkey | tee hole-priv.key | wg pubkey > hole-pub.key
+ fi
cat >wghole.conf <<EOF
[Interface]
# contents hole-priv.key
Address = 10.8.0.$ipsuf/24
# https://dev.to/tangramvision/what-they-don-t-tell-you-about-setting-up-a-wireguard-vpn-1h2g
# ||: makes the systemd service not fail due to the failed command
-PostUp = ping -c1 10.8.0.1 ||:
+PostUp = ping -w10 -c1 10.8.0.1 ||:
[Peer]
# li. called wgmail on that server
PublicKey = CTFsje45qLAU44AbX71Vo+xFJ6rt7Cu6+vdMGyWjBjU=
-AllowedIPs = 10.8.0.0/24
+AllowedIPs = 10.8.0.0/24$vpn_allowed$extrahost
Endpoint = 72.14.176.105:1194
PersistentKeepalive = 25
EOF
cedit -q $host /p/c/machine_specific/li/filesystem/etc/wireguard/wgmail.conf <<EOF || [[ $? == 1 ]]
[Peer]
PublicKey = $(cat hole-pub.key)
-AllowedIPs = 10.8.0.$ipsuf/32
+AllowedIPs = 10.8.0.$ipsuf/32,10.174.${vpn_ips[$host]}.2/32
EOF
)
}
m sudo -E /usr/bin/nsenter --mount=/root/mount_namespaces/$ns "$@"
}
+mnsd() { # mount namespace + systemd namespace
+ ns=$1
+ unit=$2
+ shift 2
+
+ s mkdir -p /root/mount_namespaces
+ if ! sudo mountpoint /root/mount_namespaces >/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
lom() {
# l = the loopback device
local l base
+ # get sudo pass cached right away
+ if ! sudo -nv 2>/dev/null; then
+ sudo -v
+ fi
if [[ $1 == /* ]]; then
base=${1##*/}
fs_file=$1
myirc() {
if [[ ! $1 ]]; then
- set -- fsf-office
+ set -- fsfsys
fi
local -a d
d=( /var/lib/znc/moddata/log/iank/{freenode,libera} )
# use * instead of -r since that does sorted order
ssh root@iankelling.org "for f in ${d[*]}; do cd \$f/#$1; grep '\<iank.*' *; done" | cut --complement -c12-16
}
+
+
+allmyirc() {
+ local d
+ d=/var/lib/znc/moddata/log/iank/freenode
+ ssh root@iankelling.org "cd $d; find . -mtime -60 -type f -exec grep '\<iank.*' {} +" | sed -r 's,^..([^/]*)/(.{11})(.{5})(.{8}).,\2\4 \1,' | sort
+}
+
+# The way pidgin logs with xmpp (maybe related to running cheogram too)
+# is that there are sometimes duplicates, and sometimes the a log file
+# is for a specific day yet logs messages for subsequent days, and the
+# only way to realize that is to notice that the timestamps rolled over
+# into a new day, you can't see it in isolation. So, basically, pidgin
+# logs are really annoying to read a grep of my messages to find the
+# date and time I said when I started and stopped working, so I'm trying
+# out a new client: profanity.
mypidgin() {
c /p/c/.purple/logs/jabber/iank@fsf.org/office@conference.fsf.org.chat
for x in *.html; do html2text -o ${x%.html}.txt $x; done;
s/^[^ ]*\.txt:\((.{2}).(.{2}).(.{4}) (.{8}) (.{2})\)?/\3-\1-\2_\4_\5/' \
| sed -n 'x;1d;0~2{G;s/\n/ /;p};${x;p}'
}
-allmyirc() {
- local d
- d=/var/lib/znc/moddata/log/iank/freenode
- ssh root@iankelling.org "cd $d; find . -mtime -60 -type f -exec grep '\<iank.*' {} +" | sed -r 's,^..([^/]*)/(.{11})(.{5})(.{8}).,\2\4 \1,' | sort
+
+# my profanity
+#
+myprof() {
+ pushd /home/iank/.local/share/profanity/chatlogs/iank_at_fsf.org/rooms/office_at_conference.fsf.org
+ logs=(*)
+ logcount=${#logs[@]}
+ if (( logcount > 15 )); then
+ i=$(( logcount - 15 ))
+ else
+ i=0
+ fi
+ # usually do this on monday, sometimes later
+ if [[ $(date +%A) == Monday ]]; then
+ min_date=$(date -d 'monday 2 weeks ago' +%s)
+ else
+ min_date=$(date -d 'monday 3 weeks ago' +%s)
+ fi
+ for (( ; i < logcount; i++ )); do
+ log=${logs[$i]}
+ d=$(date -d "$(head -n1 $log|awk '{print $1}')" +%s)
+ if (( d < min_date )); then
+ continue
+ fi
+ if awk '$3 == "iank:"' $log | sed -r 's/^(.{10}).(.{8})[^ ]+(.*)/\1_\2\3/' | grep .; then
+ hr
+ fi
+ done
+ 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
+prof-recent() {
+ case $HOSTNAME in
+ kd)
+ prof-recent-local
+ ;;
+ *)
+ ssh b8.nz prof-recent-local
+ ;;
+ 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)
+ dates=("$(date +%Y_%m_%d)" "$(date -d '1 day ago' +%Y_%m_%d)" )
+ for d in /d/p/profanity/chatlogs/iank_at_fsf.org/!(rooms); do
+ files=()
+ for date in ${dates[@]}; do
+ f=$d/$date.log
+ if [[ -e $f ]]; then
+ files+=($f)
+ fi
+ done
+ if (( ${#files[@]} >= 1 )); then
+ cat ${files[@]} | tail
+ hr
+ fi
+ done
}
+
# usage: debvm DEBIAN_VERSION RAM_MB
debvm() {
local ver ram fname src
#
# -t = get recipient from header
exim -d -t <<EOF
-From: root@$(hostname -f)
-To: root@$(hostname -f)
-Subject: test2
+From: ian@iankelling.org
+To: submit@b.b8.nz
+Subject: testbug1
+
+Package: test
+Version:1
This is a test message.
EOF
(sleep "$(calc "$* * 60")" && mpv --no-config --volume 50 /a/bin/data/alarm.mp3) > /dev/null 2>&1 &
}
+## usage: to connect to my main transmission daemon from a different host, run this
+trans-remote-route() {
+ :
+}
trg() { transmission-remote-gtk & r; }
+# TODO: this wont work transmission.lan doesnt exist
trc() {
# example, set global upload limit to 100 kilobytes:
# trc -u 100
s $ecmd "$@"
return
fi
- pid=$(pgrep -f "/usr/sbin/exim4 -bd -q30m -C /etc/exim4/my.conf"|h1)
+ pid=$(pgrep -f "/usr/sbin/exim4 -bd -q10m -C /etc/exim4/my.conf"|h1)
m s nsenter -t $pid -n -m $ecmd "$@"
}
sdncmd() { # systemd namespace cmd
- local unit pid
+ local unit pid tmpf
if (( $# <= 2 )); then
echo $0: error wrong number of args >&2
return 1
unit=$1
shift
pid=$(servicepid $unit)
- m sudo nsenter -t $pid -n -m sudo -u $USER -i "$@"
+ 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"
}
eximbash() {
local pid
- pid=$(pgrep -f "/usr/sbin/exim4 -bd -q30m -C /etc/exim4/my.conf"|h1)
+ 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
# unmute
um() {
+ local sink card
+ sink=$(pactl get-default-sink)
+ if [[ $sink != auto_null ]]; then
+ return
+ fi
+
+ # 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: <off>$/{g;p;q}')
+ m pacmd set-card-profile "$card" output:analog-stereo
+
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
}
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
}
calvis() { # calendar visualize
install -m 600 /dev/null /tmp/calendar-bytes
- while read l; do
+ while read -r l; do
for char in $l; do
+ # shellcheck disable=SC2059 # intentional for the hex formatting
printf "\x$(printf "%x" $char)" >>/tmp/calendar-bytes
done
done < <(grep -v '[#-]' /p/calendar-data)
# rg my main files
rgm() {
- rg "$@" /p/pd.org /p/w.org /a/t.org /a/work.org /b
+ rg "$@" /p/w.org /a/t.org /a/work.org /b
+}
+
+# re all my files more expansively
+rem() {
+ local paths
+ paths="/p/c /b/"
+ 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 ||:
+}
+reml() { # with limit to 5 matches per file
+ local paths
+ paths="/p/c /b"
+ 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 ||:
+}
+
+
+# for use in /f/bind
+fupzone() {
+ # shellcheck disable=SC2046 # i want word splitting
+ ./update-zone $(i s | sed -rn 's/.*db\.(.*)/\1/p')
+}
+
+# setup:
+# pip3 install linode-cli
+# linode-cli
+livp9() {
+ local input ip id tmp
+ input=$1
+ if [[ $2 ]]; then
+ id=$2
+ ip=$3
+ else
+ tmp=$(mktemp)
+ echo $tmp
+ linode-cli --json --pretty linodes create --root_pass loxHuceygomGisun | tee $tmp
+ read -r ip id <<<"$(tail -n+2 $tmp | jq -r '.[0].ipv4[0] , .[0].id')"
+ for string in $ip $id; do
+ case $string in
+ [0-9]*) : ;;
+ *)
+ echo "livp9: bad value ip=$ip id=$id input=$input"
+ return 1
+ ;;
+ esac
+ done
+ rm $tmp
+
+ while true; do
+ if timeout 4 ssh $ip :; then
+ break
+ fi
+ sleep 3
+ done
+ fi
+ ssh $ip <<EOF
+apt-get -qq update
+apt-get -qq -y install ffmpeg rsync
+mkdir vp9
+EOF
+ m rsync $input $ip:
+ m ssh $ip ffmpeg -nostdin -hide_banner -loglevel error -i $input -g 192 -vcodec libvpx-vp9 -vf scale=-1:720 -max_muxing_queue_size 9999 -b:v 750K -pass 1 -an -f null /dev/null
+ m ssh $ip ffmpeg -nostdin -hide_banner -loglevel error -y -i $input -g 192 -vcodec libvpx-vp9 -tile-rows 2 -vf scale=-1:720 -max_muxing_queue_size 9999 -b:v 750K -pass 2 -c:a libvorbis -qscale:a 5 vp9/$input
+ rsync $ip:vp9/$input vp9
+ linode-cli linodes delete $id
}
reset-konsole() {
if type -P rg &>/dev/null; then
# --no-messages because of annoying errors on broken symlinks
# -z = search .gz etc files
- # -. = search dotfilesq
+ # -. = search dotfiles
rg() { command rg -. -z --no-messages -L -i -M 900 --no-ignore-parent --no-ignore-vcs -g '!.git' -g '!auto-save-list' -g '!.savehist' "$@" || return $?; }
#fails if not exist. ignore
complete -r rg 2>/dev/null ||:
alias rg=grr
fi
+# rg with respecting vcs ignore files
+rgv() {
+ ret=0
+ # -. = search dotfiles
+ # -z = search zipped files
+ # -i = case insensitive
+ # -M = max columns
+ # --no-messages because of annoying errors on broken symlinks
+ # --no-ignore-parent because i have /a/.git which ignores almost everything under it.
+ command rg -. -z --no-messages -i -M 900 --no-ignore-parent -g '!.git' -g '!auto-save-list' -g '!.savehist' "$@" || ret=$?
+ return $ret
+}
+amall() {
+ echo "$(tput setaf 5 2>/dev/null ||:)█ coresite █$(tput sgr0 2>/dev/null||:)"
+ amfsf "$@"
+ echo "$(tput setaf 5 2>/dev/null ||:)█ office █$(tput sgr0 2>/dev/null||:)"
+ amoffice "$@"
+}
+amallq() { # amall quiet
+ amfsf "$@"
+ amoffice "$@"
+}
+amfsf() {
+ sedi -r '/alertmanager.url/s/@prom.office/@prom/' ~/.config/amtool/config.yml
+ amtool "$@"
+}
+amoffice() {
+ sedi -r '/alertmanager.url/s/@prom.fsf/@prom.office.fsf/' ~/.config/amtool/config.yml
+ amtool "$@"
+}
+amls() {
+ amall silence query "$@"
+}
+# amtool silence add
+amsa() {
+ amall silence add "$@"
+}
+# amtool silence force
+amsf() {
+ amall silence add x!="1"
+}
+amrmall() {
+ # note: not sure if quoting of this arg is correct
+ amfsf silence expire "$(amfsf silence query -q)"
+ amoffice silence expire "$(amoffice silence query -q)"
+}
+
+
+youtube-dl-update() {
+ sudo wget https://yt-dl.org/downloads/latest/youtube-dl -O /usr/local/bin/youtube-dl
+ sudo chmod a+rx /usr/local/bin/youtube-dl
+}
+
+# https://github.com/yt-dlp/yt-dlp/wiki/Installation
+yt-dlp-update() {
+ sudo curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp
+ sudo chmod a+rx /usr/local/bin/yt-dlp # Make executable
+}
+
+mpvyt() {
+ mpv --ytdl ytdl_path=/usr/local/bin/yt-dlp "$@"
+}
# taken from default changes to bashrc and bash_profile
path-add --end --ifexists $HOME/.rvm/bin
# so its included in overall env
+# ya, hacky hardcoded hostnames in 2023. we could do better
+hssh-update() {
+ local -a failed_hosts hosts
+ case $HOSTNAME in
+ sy|kd)
+ hosts=(
+ kd x3.office.fsf.org syw
+ )
+ ;;
+ x3)
+ hosts=(
+ b8.nz sywg.b8.nz
+ )
+ ;;
+ esac
+ for host in ${hosts[@]}; do
+ e $host
+ if ! scp /b/fai/fai/config/files/usr/local/bin/hssh/IANK root@$host:/usr/local/bin/hssh; then
+ failed_hosts+=($host)
+ fi
+ done
+ if (( ${#failed_hosts[@]} >= 1 )); then
+ echo failed_hosts=${failed_hosts[*]}
+ return 1
+ fi
+}
+
+
export BASEFILE_DIR=/a/bin/fai-basefiles
#export ANDROID_HOME=/a/opt/android-home