host info updates
[distro-setup] / brc2
diff --git a/brc2 b/brc2
index 5c86f00f8845b7c5f18885922fdb06c77f300cb7..3edbae0f26a47871cf1e0d733f570d0b935f8995 100644 (file)
--- a/brc2
+++ b/brc2
@@ -1,6 +1,25 @@
 #!/bin/bash
 #!/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
 
 
 # this gets sourced. shebang is just for file mode detection
 
 
@@ -64,15 +83,6 @@ else
   export NOT_MAIL_HOST_P=t
 fi
 
   export NOT_MAIL_HOST_P=t
 fi
 
-
-source /a/bin/log-quiet/logq-function
-
-# not used
-# if [[ -s /a/opt/alacritty/extra/completions/alacritty.bash ]]; then
-#   source /a/opt/alacritty/extra/completions/alacritty.bash
-# fi
-
-
 source /a/bin/ds/beet-data
 
 
 source /a/bin/ds/beet-data
 
 
@@ -162,7 +172,7 @@ slemacs() {
 
 sle() { # sl emacs
   local f=/home/iank/.emacs.d/init.el
 
 sle() { # sl emacs
   local f=/home/iank/.emacs.d/init.el
-  sl --sl-test-cmd ". /etc/os-release ; printf %s \${VERSION//[^a-zA-Z0-9]/}; test -e $f && stat -c%Y $f" --sl-test-hook slemacs "$@"
+  sl --sl-test-cmd "sed -rn '/^VERSION=/{s/^.*=//;s/[^[:alnum:]]//gp}' /etc/os-release; test -e $f && stat -c%Y $f" --sl-test-hook slemacs "$@"
 }
 ccomp ssh sle
 
 }
 ccomp ssh sle
 
@@ -197,6 +207,20 @@ rm-docker-iptables() {
 
 # usage mkschroot [-] distro codename packages
 # - means no piping in of sources.list
 
 # 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 <<EOF
+# $USER  ALL=(ALL)  NOPASSWD: ALL
+# Defaults  env_keep += SUDOD
+# Defaults always_set_home
+# Defaults !umask
+# EOF
+# sd /nocow/schroot/flidas//etc/locale.gen <<'EOF'
+# en_US.UTF-8 UTF-8
+# EOF
+# s schroot -c flidas locale-gen
+# s schroot -c flidas update-locale LANG=en_US.UTF-8
+
 mkschroot() {
   local sources force repo n distro
   force=false
 mkschroot() {
   local sources force repo n distro
   force=false
@@ -368,11 +392,6 @@ cp-blocked-domains-to-ansible() {
 }
 
 
 }
 
 
-anki() {
-  # crashes on adding new cards in t9
-  schroot -c buster -- anki
-}
-
 daycat() {
   ngset
   hrcat /m/md/daylert/{cur,new}/*
 daycat() {
   ngset
   hrcat /m/md/daylert/{cur,new}/*
@@ -454,7 +473,7 @@ glue() {
 
 # usage: see above
 _iki-convert() {
 
 # usage: see above
 _iki-convert() {
-  local url url_prefix path input err repo_dir dir url_dir url name
+  local url url_prefix path input repo_dir dir url_dir url name
   url_prefix="$1"
   name="${url_prefix%%.*}"
   repo_dir="/f/$name"
   url_prefix="$1"
   name="${url_prefix%%.*}"
   repo_dir="/f/$name"
@@ -467,8 +486,16 @@ _iki-convert() {
   case $input in
     http*)
       path="$repo_dir/${input##http*://"$url_prefix"/}"
   case $input in
     http*)
       path="$repo_dir/${input##http*://"$url_prefix"/}"
+      # for files like x.jpg, we dont need to convert the extension.
       if [[ $path == */ ]]; then
         path=${path%/}.mdwn
       if [[ $path == */ ]]; then
         path=${path%/}.mdwn
+        # brains adds trailing slash, but without trailing is still
+        # valid. We can't be totally sure whether to add mdwn, but we
+        # can guess based on the existence of the file. We can't be sure
+        # because it could be a file like x.jpg, that we just don't have
+        # in our local repo.
+      elif [[ ! -f $path && -e $path.mdwn ]]; then
+        path=${path}.mdwn
       fi
       j printf "%s\n" "$path"
       ;;
       fi
       j printf "%s\n" "$path"
       ;;
@@ -476,7 +503,9 @@ _iki-convert() {
       path=$(fp "$input")
       url_dir=$(echo "$path" | sed -r "s,^(/a)?$repo_dir/,,")
       url="https://$url_prefix/$url_dir"
       path=$(fp "$input")
       url_dir=$(echo "$path" | sed -r "s,^(/a)?$repo_dir/,,")
       url="https://$url_prefix/$url_dir"
-      url="${url%.mdwn}/"
+      if [[ $url == *.mdwn ]]; then
+        url="${url%.mdwn}/"
+      fi
       j echo "$url"
       ;;
   esac
       j echo "$url"
       ;;
   esac
@@ -739,6 +768,7 @@ mpvrpc-percent-pos() {
 # 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() {
 # 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
   if ps h -o args -C "${1##*/}" | grep -Fxqv "$*" &>/dev/null || [[ $? == 141 ]]; then
     "$@"
   fi
@@ -771,7 +801,7 @@ mpvrpc-loadfile() {
     finalpath="$cachedir${path#/i/m}"
     rowir rsync --partial -a --inplace --mkpath "b8.nz:$path" "$finalpath"
     finalnextpath="$cachedir${nextpath#/i/m}"
     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 $cachdir" || [[ $? == 1 ]] )
+    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" &
     # allow us to start 2 rsyncs in the background
     if [[ $count == [01] ]]; then
       rinr rsync --partial -a --inplace --mkpath "b8.nz:$nextpath" "$finalnextpath" &
@@ -801,9 +831,10 @@ mpvrpc-loadfile() {
 # q quit
 # ret next
 #
 # q quit
 # ret next
 #
+# 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
 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 do_rare_genres read_wait 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 repeat1
   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 repeat1
@@ -1752,19 +1783,13 @@ bindpush() {
   dsign iankelling.org expertpathologyreview.com zroe.org amnimal.ninja
   lipush
   for h in li bk; do
   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
   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
 }
 
   done
 }
 
@@ -1775,8 +1800,18 @@ dnsup() {
 dnsb8() {
   local f=/var/lib/bind/db.b8.nz
   m ser stop named
 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
 }
   m sudo install -m 644 -o bind -g bind /p/c/machine_specific/vps/bind-initial/db.b8.nz $f
   m ser restart named
 }
@@ -1953,6 +1988,71 @@ capache()
   fi
 }
 
   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
 chrome() {
   if type -p chromium &>/dev/null; then
     cmd=chromium
@@ -2240,8 +2340,8 @@ rename-test() {
   # test whether missing files were renamed, generally for use with fsdiff
   # $1 = fsdiff output file, $2 = directory to compare to. pwd = fsdiff dir
   # echos non-renamed files
   # test whether missing files were renamed, generally for use with fsdiff
   # $1 = fsdiff output file, $2 = directory to compare to. pwd = fsdiff dir
   # echos non-renamed files
-  local x y found
-  unset sums
+  local x line found renamed
+  local -a sums
   for x in "$2"/*; do
     { sums+=( "$(md5sum < "$x")" ) ; } 2>/dev/null
   done
   for x in "$2"/*; do
     { sums+=( "$(md5sum < "$x")" ) ; } 2>/dev/null
   done
@@ -2293,8 +2393,8 @@ gup() { /a/f/gnulib/build-aux/gnupload "$@"; }
 
 dejagnu() { /a/opt/dejagnu/dejagnu "$@"; }
 
 
 dejagnu() { /a/opt/dejagnu/dejagnu "$@"; }
 
+# do git status on published repos.
 hstatus() {
 hstatus() {
-  # do git status on published repos.
   c /a/bin/githtml
   for x in *; do
     cd "$(readlink -f $x)"/..
   c /a/bin/githtml
   for x in *; do
     cd "$(readlink -f $x)"/..
@@ -2308,6 +2408,16 @@ hstatus() {
   done
 }
 
   done
 }
 
+hsk() {
+  local x
+  c /a/bin/githtml
+  for x in *; do
+    cd "$(readlink -f $x)"/..
+    skgit
+    cd /a/bin/githtml
+  done
+}
+
 ## work log
 #
 # note: database location is specified in ~/.timetrap.yml, currently /p/.timetrap.db
 ## work log
 #
 # note: database location is specified in ~/.timetrap.yml, currently /p/.timetrap.db
@@ -2457,15 +2567,21 @@ ilog-local() {
     cd $d$n/"$chan"
     hr
     for x in *; do
     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
 }
 ilog() {
     done
   done
 }
 ilog() {
-  local chan
+  local chan tmpf
+  tmpf=$(mktemp)
   chan="${1:-#fsfsys}"
   # use * instead of -r since that does sorted order
   chan="${1:-#fsfsys}"
   # use * instead of -r since that does sorted order
-  sl root@iankelling.org ilog-local "$chan" | less +G
+  sl root@li.b8.nz ilog-local "$chan" > $tmpf
+  less +G $tmpf
+  rm -f $tmpf
 }
 
 o() {
 }
 
 o() {
@@ -2520,22 +2636,138 @@ wgkey() {
   umask $umask_orig
 }
 
   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[s23b]=49
+host-info-all() {
+  host-info-update
+  bindpushb8
+  ssh iank@li.b8.nz conflink
+  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 all_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
+
+    # opt parsing
+    vpn=false
+    root=false
+    for opt in $opts; do
+      case $opt in
+        user=root)
+          root=true
+          ;;
+        vpn)
+          vpn=true
+          ;;
+      esac
+    done
+
+    all_ips[$host]=$ip
+    if $vpn; then
+      vpn_ips[$host]=$ip
+    else
+      nonvpn_ips[$host]=$ip
+    fi
+    if $root; then
+      # note: the reason we have b8.nz suffix here but not for non_root
+      # hosts is that it is for the User part, the IdentityFile part is
+      # redundant to *.b8.nz. Also note ${host}i, we only setup those for vpn hosts, but there is no harm in overspecifying here.
+      root_hosts+=($host ${host}i $host.b8.nz ${host}i.b8.nz)
+      root_hosts_a[$host]=t  # a for associative array
+    else
+      nonroot_hosts+=($host ${host}i)
+    fi
+    host_ips[$host]=$ip
+    if [[ $mac ]]; then
+      host_macs[$host]=$mac
+    fi
+
+  done </p/c/host-info
+
+  {
+    cat <<EOF
+Host ${nonroot_hosts[@]}
+User iank
+IdentityFile ~/.ssh/home
+
+Host ${root_hosts[@]}
+IdentityFile ~/.ssh/home
+
+EOF
+    for host in ${!vpn_ips[@]}; do
+      ipsuf=${vpn_ips[$host]}
+      cat <<EOF
+Host ${host}i
+Hostname b8.nz
+Port $((2200 + ipsuf))
+
+EOF
+    done
+
+    # convenience of one auth key entry
+    for host in ${!all_ips[@]}; do
+      cat <<EOF
+Host $host ${host}i $host.b8.nz ${host}i.b8.nz
+HostKeyAlias $host.b8.nz
+EOF
+    done
+  } | cedit /p/c/subdir_files/.ssh/config || [[ $? == 1 ]]
+
+  {
+    # hack to please emacs parser
+    here_begin="cat <<EOF"
+    echo "$here_begin"
+    for host in ${!vpn_ips[@]}; do
+      ipsuf=${vpn_ips[$host]}
+      i_port=$(( 2200 + ipsuf ))
+      cat <<EOF
+config redirect
+option name ssh$host
+option src              wan
+option src_dport        $i_port
+option dest_port        22
+option dest_ip          \$l.$ipsuf
+option dest             lan
+config rule
+option src              wan
+option target           ACCEPT
+option dest_port        $i_port
+EOF
+    done
+    echo "EOF"
+  } >/p/c/cmc-firewall-data
+
 
 
-vpn-ips-update() {
   local host ipsuf f files
   local host ipsuf f files
+
+  # shellcheck disable=SC2016 # shellcheck doesnt know this is sed
+  sedi '/edits below here are made automatically/,$d' /p/c/machine_specific/li/filesystem/etc/wireguard/wgmail.conf
   for host in ${!vpn_ips[@]}; do
   for host in ${!vpn_ips[@]}; do
+    if [[ ${root_hosts_a[$host]} ]]; then
+      # root machines dont actually need vpn, but
+      # the classification still helps with other
+      # configurations.
+      continue
+    fi
     ipsuf=${vpn_ips[$host]}
     wghole $host $ipsuf
     ipsuf=${vpn_ips[$host]}
     wghole $host $ipsuf
+    u /b/ds/machine_specific/li/filesystem/etc/openvpn/client-config-hole/$host <<EOF
+ifconfig-push 10.5.5.${vpn_ips[$host]} 255.255.255.0
+EOF
     u /a/bin/ds/machine_specific/$host/filesystem/etc/systemd/system/openvpn-client-tr@.service <<EOF
 [Unit]
 Description=OpenVPN tunnel for %I
     u /a/bin/ds/machine_specific/$host/filesystem/etc/systemd/system/openvpn-client-tr@.service <<EOF
 [Unit]
 Description=OpenVPN tunnel for %I
@@ -2577,15 +2809,36 @@ EOF
   done
 
   {
   done
 
   {
-    for host in ${!vpn_ips[@]}; do
-      ipsuf=${vpn_ips[$host]}
-      cat <<EOF
-local-data-ptr: "10.2.0.$ipsuf $host.b8.nz"
-EOF
+    echo "cat <<EOF"
+    for host in ${!host_ips[@]}; do
+      ipsuf=${host_ips[$host]}
+      # shellcheck disable=SC2016 # intentional
+      echo 'local-data-ptr: "$l.'$ipsuf $host.b8.nz'"'
+    done
+    echo "EOF"
+  } | u /p/c/ptr-data
+
+  {
+    echo "cat <<EOF"
+    for host in ${!host_macs[@]}; do
+      ipsuf=${host_ips[$host]}
+      echo "dhcp-host=${host_macs[$host]},set:$host,\$l.$ipsuf,$host"
     done
     done
-  } | u /b/ds/ptr-data
+    echo "EOF"
+  } | u /p/c/dnsmasq-data
+
 
 
+  b8_ip=$(dig +short b8.nz @iankelling.org | tail -1)
+  if [[ ! $b8_ip ]]; then
+    echo "$0: error: got empty b8.nz ip. returning 1"
+    return 1
+  fi
   {
   {
+    echo "@    A       $b8_ip"
+    for host in ${!nonvpn_ips[@]}; do
+      ipsuf=${nonvpn_ips[$host]}
+      echo "$host      A       10.2.0.$ipsuf"
+    done
     for host in ${!vpn_ips[@]}; do
       ipsuf=${vpn_ips[$host]}
       cat <<EOF
     for host in ${!vpn_ips[@]}; do
       ipsuf=${vpn_ips[$host]}
       cat <<EOF
@@ -2600,31 +2853,41 @@ EOF
 
   echo checking for stray files:
 
 
   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
+  initial_dir="$PWD"
+  while read -r dir path; do
+    cd $dir
+    ngset
+    files=( */$path )
+    ngreset
+    cd "$initial_dir"
+    for f in "${files[@]}"; do
+      host=${f%%/*}
+      if [[ ! ${vpn_ips[$host]} ]]; then
+        e rm $dir/$f
+      fi
+    done
+  done <<'EOF'
+/a/bin/ds/machine_specific filesystem/etc/systemd/system/openvpn-client-tr@.service
+/p/c/machine_specific filesystem/etc/wireguard/wghole.conf
+EOF
 
 
-  cd /p/c/machine_specific
-  ngset
-  files=( */filesystem/etc/wireguard/wghole.conf )
-  ngreset
-  cd $initial_dir
+  files=( /b/ds/machine_specific/li/filesystem/etc/openvpn/client-config-hole/* )
   for f in "${files[@]}"; do
   for f in "${files[@]}"; do
-    host=${f%%/*}
+    host=${f##*/}
     if [[ ! ${vpn_ips[$host]} ]]; then
     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 '<<<""'
+      e rm $f
+      e ssh root@li.b8.nz rm -f $f
     fi
   done
     fi
   done
+
+
+  {
+    printf "%s" "Host * "
+    sed -n '/^Host /h;/^IdentityFile .*\/home/{g;s/^Host//;s/ / !/gp}' ~/.ssh/config | tr '\n' ' '
+    echo "IdentityFile ~/.ssh/work"
+  } | cedit work-identity ~/.ssh/config || [[ $? == 1 ]]
+
+
 }
 
 # usage host ipsuf [extrahost]
 }
 
 # usage host ipsuf [extrahost]
@@ -2842,7 +3105,7 @@ mdenable() {
 
   two=false
   case $1 in
 
   two=false
   case $1 in
-    -2) two=true shift ;;
+    -2) two=true; shift ;;
   esac
 
   for md; do
   esac
 
   for md; do
@@ -2923,6 +3186,9 @@ mpvgpu() {
 mpvd() {
   mpv --profile=d "$@";
 }
 mpvd() {
   mpv --profile=d "$@";
 }
+mpva() {
+  mpv --profile=a "$@";
+}
 # mpv all media files in . or $1
 mpvm() {
   local -a extensions arg
 # mpv all media files in . or $1
 mpvm() {
   local -a extensions arg
@@ -3402,8 +3668,6 @@ spd() {
 }
 
 spamf() { # spamtest on FILE
 }
 
 spamf() { # spamtest on FILE
-  local spamcpre spamdpid
-
   if (( $# != 1 )); then
     e spamtest error: expected 1 arg, filename >&2
     return 1
   if (( $# != 1 )); then
     e spamtest error: expected 1 arg, filename >&2
     return 1
@@ -4007,12 +4271,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
 electrum() {
   # https://electrum.readthedocs.io/en/latest/tor.html
   # https://github.com/spesmilo/electrum-docs/issues/129
@@ -4024,6 +4282,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
 # rg my main files
 rgm() {
   rg "$@" /p/w.org /a/t.org /a/work.org /b
@@ -4036,17 +4300,27 @@ 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 -- "$*" ||:
   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() { # with limit to 5 matches per file
+reml() { # rem with limit to 5 matches per file
+  local_rgv_args="-m 5"
+  rem "$@"
+}
+
+rep() {
   local paths
   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 -- "$*" ||:
   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
 # re on common fsf files
 ref() {
   local paths
@@ -4193,9 +4467,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
 
 # I have the git repo and a release. either one should work.
 # I have both because I was trying to solve an issue that
@@ -4305,7 +4576,7 @@ hssh-update() {
   case $HOSTNAME in
     sy|kd)
       hosts=(
   case $HOSTNAME in
     sy|kd)
       hosts=(
-        kd x3.office.fsf.org syw
+        kd.b8.nz x3.office.fsf.org syw x2.b8.nz
       )
       ;;
     x3)
       )
       ;;
     x3)
@@ -4357,6 +4628,54 @@ ftoc() {
   units "tempF($1)" tempC
 }
 
   units "tempF($1)" tempC
 }
 
+# requires dns/firewall setup first
+local-icecast() {
+  web-conf -e ian@iankelling.org -f 8000 - apache2 live.iankelling.org  <<'EOF'
+<Location "/fsf.webm">
+AuthType Basic
+AuthName "basic_auth"
+# created with
+# htpasswd -c icecast-fsf-htpasswd USERNAME
+AuthUserFile "/etc/icecast-fsf-htpasswd"
+Require valid-user
+</Location>
+<Location "/fsf-tech.webm">
+AuthType Basic
+AuthName "basic_auth"
+AuthUserFile "/etc/icecast-fsf-tech-htpasswd"
+Require valid-user
+</Location>
+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<COLUMNS; i++)); do
+    echo
+  done
+}
+
+
 export BASEFILE_DIR=/a/bin/fai-basefiles
 
 #export ANDROID_HOME=/a/opt/android-home
 export BASEFILE_DIR=/a/bin/fai-basefiles
 
 #export ANDROID_HOME=/a/opt/android-home