X-Git-Url: https://iankelling.org/git/?a=blobdiff_plain;f=brc2;h=a28d7b7e970a94cc580735002110a3ea675df1b4;hb=7b33a0e88d9ccdaf8601aa77f9fc597d592b4c10;hp=32ac77a4219ff33b15dbe858ac7d05903c51f46b;hpb=21bddd1d26a0349f3932f12c65fbc0775e855880;p=distro-setup diff --git a/brc2 b/brc2 index 32ac77a..a28d7b7 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 @@ -197,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. @@ -787,7 +879,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 @@ -916,13 +1009,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 @@ -960,7 +1053,7 @@ beetag() { doplay=false else doplay=true - mpvrpc '{ "command": ["loadfile", "'"$path"'"] }' + mpvrpc-loadfile "$path" erasable_line=false fi beetag-nostatus 1 @@ -1698,7 +1791,8 @@ bindpush() { dsign iankelling.org expertpathologyreview.com zroe.org amnimal.ninja lipush for h in li bk; do - m sl $h.b8.nz <<'EOF' + e sshing $h + ssh $h.b8.nz <<'EOF' source ~/.bashrc m dnsup EOF @@ -1707,7 +1801,8 @@ EOF bindpushb8() { lipush for h in li bk; do - m sl $h <<'EOF' + e sshing $h + ssh $h.b8.nz <<'EOF' source ~/.bashrc m dnsb8 EOF @@ -1808,9 +1903,13 @@ satoshi() { # $1 satoshi in usd } # Bitcoin holds open the wallet file. this causes problems for a -# secondary computer running bitcoin and receiving a backup. So, as a -# workaround, I intend to manually enable the wallet when I want to use -# it and leave it disabled otherwise. +# 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 @@ -1856,9 +1955,13 @@ walletoff() { 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 @@ -1891,6 +1994,70 @@ 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() { + 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 @@ -1939,10 +2106,6 @@ digme() { digdiff @ns{1,2}.iankelling.org "$@" } -tsr() { # ts run - "$@" |& ts || return $? -} - dup() { local ran_d ran_d=false @@ -2399,7 +2562,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 } @@ -2471,6 +2637,7 @@ vpn_ips[x2]=13 vpn_ips[kw]=27 vpn_ips[bo]=28 vpn_ips[frodo]=34 +vpn_ips[s23b]=49 vpn-ips-update() { local host ipsuf f files @@ -2864,6 +3031,9 @@ mpvgpu() { mpvd() { mpv --profile=d "$@"; } +mpva() { + mpv --profile=a "$@"; +} # mpv all media files in . or $1 mpvm() { local -a extensions arg @@ -3172,7 +3342,7 @@ j() { "$@" |& pee "xclip -r -selection clipboard" cat } -# x copy +# xorg copy. copy text piped into command xc() { xclip -r -selection clipboard } @@ -3343,16 +3513,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" } @@ -3596,16 +3761,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 @@ -3647,7 +3812,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 @@ -3659,9 +3824,11 @@ sdnbashroot() { # systemd namespace bash } -sdncmd() { # systemd namespace cmd +# systemd namespace cmd +# usage: UNIT CMD... +sdncmd() { local unit pid tmpf - if (( $# <= 2 )); then + if (( $# <= 1 )); then echo $0: error wrong number of args >&2 return 1 fi @@ -3675,6 +3842,18 @@ sdncmd() { # systemd namespace cmd 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 + echo $0: error wrong number of args >&2 + return 1 + fi + unit=$1 + shift + pid=$(servicepid $unit) + m sudo nsenter -t $pid -n -m "$@" +} + mailnnbash() { sdnbash mailnn @@ -3686,13 +3865,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 @@ -3700,7 +3873,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() { @@ -3734,14 +3907,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 } @@ -3779,17 +3951,15 @@ fixu() { um() { local sink card sink=$(pactl get-default-sink) - if [[ $sink != auto_null ]]; then - return + 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 - # 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 - - pactl set-sink-mute @DEFAULT_SINK@ false + m pactl set-sink-mute @DEFAULT_SINK@ false rm -f /tmp/ianknap } @@ -3946,12 +4116,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 @@ -3969,21 +4133,42 @@ rgm() { } # 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 ||: + 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 ||: } @@ -4122,9 +4307,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 @@ -4255,6 +4437,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