lots of fixes, automation for bitfolk
[distro-setup] / brc2
1 #!/bin/bash
2 # Copyright (C) 2019 Ian Kelling
3 # SPDX-License-Identifier: AGPL-3.0-or-later
4 # this gets sourced. shebang is just for file mode detection
5
6
7 # * settings
8
9 HISTFILE=$HOME/.bh
10
11 source /a/bin/distro-setup/path-add-function
12 path-add /a/exe
13 # add this with absolute paths as needed for better security
14 #path-add --end /path/to/node_modules/.bin
15
16 # pip3 --user things go here:
17 path-add --end ~/.local/bin
18 path-add --ifexists --end /a/work/libremanage
19 path-add --ifexists --end /a/opt/adt-bundle*/tools /a/opt/adt-bundle*/platform-tools
20 path-add --ifexists --end /a/opt/scancode-toolkit-3.10.
21
22
23 export WCDHOME=/a
24
25
26 case $EUID in
27 0)
28 SL_SSH_ARGS="-F $HOME/.ssh/confighome"
29 ;;
30 esac
31
32
33 # * include files
34
35 # generated instead of dynamic for the benefit of shellcheck
36 #for x in /a/bin/distro-functions/src/* /a/bin/!(githtml)/*-function?(s); do echo source $x ; done
37 source /a/bin/distro-functions/src/identify-distros
38 source /a/bin/log-quiet/logq-function
39 # for x in /a/bin/bash_unpublished/source-!(.#*); do echo source $x; done
40 source /a/bin/bash_unpublished/source-semi-priv
41 source /a/bin/bash_unpublished/source-state
42
43 source /a/bin/log-quiet/logq-function
44 if [[ -s /a/opt/alacritty/extra/completions/alacritty.bash ]]; then
45 source /a/opt/alacritty/extra/completions/alacritty.bash
46 fi
47
48
49 # * functions
50
51 hstest() {
52 install-my-scripts
53 d=$(mktemp -d)
54 sed '/^ *IdentityFile/d' ~/.ssh/config >$d/config
55 s command ssh -F $d/config -i /q/root/h "$@"
56 }
57
58 hrtest() {
59 install-my-scripts
60 d=$(mktemp -d)
61 sed '/^ *IdentityFile/d' ~/.ssh/config >$d/config
62 s rsync -e "ssh -F $d/config -i /q/root/h" "$@"
63 }
64
65
66 slemacs() {
67 local arg rtime v
68 arg="$1"
69 remote="$2"
70 if [[ $arg == [89]0Etiona* ]]; then
71 v=${arg::1}
72 rtime=${arg#*Etiona} # remote time
73 if [[ ! $rtime ]]; then
74 rtime=0
75 fi
76 dir=/a/opt/emacs-trisquel${v}-nox/.iank
77 ltime=$(stat -c%Y $dir/e/e/.emacs.d/init.el)
78 if (( ltime > rtime )); then
79 m rsync -rptL --delete --filter=". /b/ds/sl/rsync-filter" $dir "$remote":/home/iank
80 fi
81 fi
82 }
83
84 sle() { # sl emacs
85 local f=/home/iank/.emacs.d/init.el
86 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 "$@"
87 }
88 ccomp ssh sle
89
90 # Run this manually after .emacs.d changes. Otherwise, to check if
91 # files changed with find takes 90ms. sl normally only adds 25ms. We
92 # could cut it down to 10ms if we put things on a btrfs filesystem and
93 # looked for changes there, or used some inotify thing, but that seems
94 # like too much work.
95 egh() { # emacs gnuhope
96 RSYNC_RSH=ssh m rsync -rptL --delete --filter=". /b/ds/sl/rsync-filter" /a/opt/emacs-trisquel9-nox/.iank lists2d.fsf.org:.ianktrisquel_9
97 RSYNC_RSH=ssh m rsync -rptL --delete --filter=". /b/ds/sl/rsync-filter" /a/opt/emacs-trisquel8-nox/.iank lists2d.fsf.org:/home/iank
98 }
99 ekw() {
100 local shell="bash -s"
101 if [[ $HOSTNAME != kw ]]; then
102 shell="ssh kw.office.fsf.org"
103 bbk -m /a -t kw
104 fi
105 $shell <<'EOF'
106 sudo mkdir /root/.ianktrisquel_9
107 sudo rsync -rptL --delete --filter=". /b/ds/sl/rsync-filter" /a/opt/emacs-trisquel9-nox/.iank /root/.ianktrisquel_9
108 rsync -rptL --delete --filter=". /b/ds/sl/rsync-filter" /a/opt/emacs-trisquel8-nox/.iank /home/iank
109 EOF
110 }
111
112 # usage mkschroot [-] distro codename packages
113 # - means no piping in of sources.list
114 mkschroot() {
115 local force=false
116 while [[ $1 == -* ]]; do
117 case $1 in
118 -f) force=true; shift ;;
119 -s)
120 sources="$2"
121 if [[ ! -s $sources ]]; then
122 echo mkschroot: error: sources file $sources does not exist or is empty
123 return 1
124 fi
125 shift 2
126 ;;
127 esac
128 done
129 distro=$1
130 shift
131 case $distro in
132 trisquel)
133 repo=http://mirror.fsf.org/trisquel/
134 ;;
135 ubuntu)
136 repo=http://archive.ubuntu.com/ubuntu/
137 ;;
138 debian)
139 repo=http://deb.debian.org/debian/
140 ;;
141 esac
142 n=$1
143
144 shift
145 if ! $force && schroot -l | grep -xFq chroot:$n; then
146 echo "$0: $n schroot already installed, skipping"
147 return 0
148 fi
149 apps=($@)
150 d=/nocow/schroot/$n
151 sd /etc/schroot/chroot.d/$n.conf <<EOF
152 [$n]
153 description=$n
154 type=directory
155 directory=$d
156 profile=desktop
157 preserve-environment=true
158 users=$USER,user2
159 EOF
160 cd
161 if [[ ! -e $d/bin ]]; then
162 sudo mkdir -p $d
163 # resolvconf otherwise schroot fails with
164 # cp: not writing through dangling symlink '/var/run/schroot/mount/flidas-7a2362e0-81b3-4848-92c1-610203ef5976/etc/resolv.conf'
165 sudo debootstrap --exclude=resolvconf $n $d $repo
166 fi
167 if [[ $sources ]]; then
168 sudo install -m 644 $sources $d/etc/apt/sources.list
169 fi
170 sudo chroot $d apt-get update
171 sudo DEBIAN_FRONTEND=noninteractive chroot $d apt-get -y dist-upgrade --purge --auto-remove
172 sudo cp -P {,$d}/etc/localtime
173 if (( ${#apps[@]} )); then
174 sudo DEBIAN_FRONTEND=noninteractive schroot -c $n -- apt-get install --allow-unauthenticated -y ${apps[@]}
175 fi
176 }
177
178
179 # note: this is incomplete and untested.
180 # https://wiki.archlinux.org/index.php/Install_Arch_Linux_from_existing_Linux#Creating_a_chroot
181 mkarchchroot() {
182 local tarball mirror
183 mirror=https://mirrors.edge.kernel.org/archlinux/iso/latest/
184 tarball=$(curl -s $mirror | sed -nr 's/.*"(archlinux-bootstrap-.*-x86_64.tar.gz)".*/\1/p')
185 wget -O /tmp/arch.tar.gz https://mirrors.edge.kernel.org/archlinux/iso/latest/$tarball
186 s mkdir -p /nocow/schroot/arch
187 cd _/nocow/schroot/arch
188 s sed -i '/## United States/,/^$/s,^#,,' etc/pacman.d/mirrorlist
189 # error: could not determine cachedir mount point /var/cache/pacman/pkg
190 s sed -i /^CheckSpace/d etc/pacman.conf
191 chroot . /bin/bash -s <<'EOF'
192 pacman-key --init
193 pacman-key --populate archlinux
194 pacman -Syyu
195 EOF
196 # example of building an aur package:
197 # pacman -Sy base-devel wget
198 # useradd -m iank
199 # f=$target/etc/sudoers
200 # line='iank ALL=(ALL) NOPASSWD: ALL'
201 # if [[ ! -e $f ]] || ! grep -xF "$line" $f; then
202 # echo "$line" >> $f
203 # fi
204 # su iank
205 # wget https://aur.archlinux.org/cgit/aur.git/snapshot/anbox-image-gapps.tar.gz
206 # tar xzf anbox-image-gapps.tar.gz
207 # cd anbox-image-gapps
208 # makepkg -s
209 }
210
211
212 # clock back in to timetrack from last entry
213 tback() {
214 sqlite3 /p/.timetrap.db "update entries set end = NULL where id = (select max(id) from entries);"
215 }
216
217 # sshfs example:
218 # s sshfs bu@$host:/bu/home/md /bu/mnt -o reconnect,ServerAliveInterval=20,ServerAliveCountMax=30 -o allow_other
219
220 eqgo() {
221 enn -M $(exiqgrep -i)
222 }
223 eqgo1() {
224 enn -M $(exiqgrep -i|h1)
225 }
226
227
228 gnupload(){
229 /a/f/gnulib/build-aux/gnupload "$@"
230 }
231
232 abrowserrmcompat() {
233 local f
234 ngset
235 f=(/p/c/firefox*/compatibility.ini)
236 if (( ${#f[@]} )); then
237 rm ${f[@]}
238 fi
239 ngreset
240 }
241 ngset() {
242 if shopt nullglob >/dev/null; then
243 ngreset=false
244 else
245 shopt -s nullglob
246 ngreset=true
247 fi
248 }
249 ngreset() {
250 if $ngreset; then
251 shopt -u nullglob
252 fi
253 }
254
255 checkre() {
256 s checkrestart -b /a/bin/ds/checkrestart-blacklist -pv
257 }
258
259 cp-blocked-domains-to-brains() {
260 cp /a/f/ans/roles/exim/files/mx/simple/etc/exim4/bad-sender_domains /a/f/brains/sysadmin/kb/blocked_email_domains.mdwn
261 }
262 cp-blocked-domains-to-ansible() {
263 cp /a/f/brains/sysadmin/kb/blocked_email_domains.mdwn /a/f/ans/roles/exim/files/mx/simple/etc/exim4/bad-sender_domains
264 }
265
266
267 anki() {
268 # crashes on adding new cards in t9
269 schroot -c buster -- anki
270 }
271
272 acat() {
273 ngset
274 hrcat /m/md/alerts/{cur,new}/*
275 ngreset
276 hr; echo bk; hr
277 ssh bk.b8.nz "shopt -s nullglob; hrcat /m/md/INBOX/new/* /m/md/INBOX/cur/*"
278 }
279 aclear() {
280 ngset
281 rm -f /m/md/alerts/{cur,new}/*
282 ngreset
283 ssh bk.b8.nz "shopt -s nullglob; rm -f /m/md/INBOX/new/* /m/md/INBOX/cur/*"
284 system-status _
285 }
286
287 alerts() {
288 find /var/local/cron-errors /home/iank/cron-errors /sysd-mail-once-state -type f
289 }
290 ralerts() { # remote alerts
291 local ret shell
292 # this list is duplicated in check-remote-mailqs
293 for h in bk je li frodo kwwg x3wg x2wg kdwg sywg; do
294 echo $h:
295 shell="ssh $h"
296 if [[ $HOSTNAME == "${h%wg}" ]]; then
297 shell=
298 fi
299 ret=0
300 $shell find /var/local/cron-errors /home/iank/cron-errors /sysd-mail-once-state -type f || ret=$?
301 if (( ret )); then
302 echo ret:$ret
303 fi
304 done
305 }
306
307 ap() {
308 # pushd in case current directory has an ansible.cfg file
309 pushd /a/xans >/dev/null
310 ansible-playbook -v -l ${1:- $(hostname -f)} site.yml
311 popd >/dev/null
312 }
313 aw() {
314 pushd /a/work/ans >/dev/null
315 time ansible-playbook -v -i inventory adhoc.yml "$@"
316 popd >/dev/null
317 }
318 ad() {
319 pushd /a/bin/distro-setup/a >/dev/null
320 ansible-playbook site.yml "$@"
321 popd >/dev/null
322 }
323
324 astudio() {
325 # googling android emulator libGL error: failed to load driver: r600
326 # lead to http://stackoverflow.com/a/36625175/14456
327 export ANDROID_EMULATOR_USE_SYSTEM_LIBS=1
328 /a/opt/android-studio/bin/studio.sh "$@" &r;
329 }
330
331 # note, to check for glue records
332 # First, find some the .org nameservers:
333 # dig +trace iankelling.org
334 # then, query one:
335 # dig ns1.iankelling.org @b0.org.afilias-nst.org.
336
337 # Now, compare for a domain that does have glue records setup (note the A
338 # and AAAA records in ADDITIONAL SECTION, those are glue records like the
339 # one I'm asking for):
340
341 # $ dig ns1.gnu.org @b0.org.afilias-nst.org.
342
343 # todo: make sm pull/push use systemd instead of the journal cat command
344 bbk() { # btrbk wrapper
345 local ret=0
346 c /
347 local active=true
348 systemctl is-active btrbk.timer || active=false
349 if $active; then
350 ser stop btrbk.timer
351 fi
352 if [[ $(systemctl is-active btrbk.service ||:) != inactive ]]; then
353 echo "cron btrbk is already running"
354 if $active; then ser start btrbk.timer; fi
355 return 1
356 fi
357 # run latest
358 install-my-scripts
359 # todo: consider changing this to srun and having the args come
360 # from a file like /etc/default/btrbk, like is done in exim
361 s jrun btrbk-run "$@"
362 if $active; then
363 if (( ret )); then
364 echo bbk: WARNING: btrbk.timer not restarted due to failure
365 else
366 ser start btrbk.timer
367 fi
368 fi
369 return $ret
370 }
371
372 faimon() {
373 fai-monitor | pee cat "fai-monitor-gui -"
374 }
375
376 bfg() { java -jar /a/opt/bfg-1.12.14.jar "$@"; }
377
378 bigclock() {
379 xclock -digital -update 1 -face 'arial black-80:bold'
380 }
381
382 nnn() { /a/opt/nnn -H "$@"; }
383
384 locat() { # log-once cat
385 local files
386 ngset
387 files=(/var/local/cron-errors/* /home/iank/cron-errors/* /sysd-mail-once-state/*)
388 case ${#files[@]} in
389 0) : ;;
390 1)
391 echo ${files[0]}
392 head ${files[0]}
393 ;;
394 *)
395 head ${files[@]}
396 ;;
397 esac
398 ngreset
399 }
400
401 # duplicated somewhat below.
402 jrun() { # journal run. run args, log to journal, tail and grep the journal.
403 # Note, an alternative without systemd would be something like ts.
404 # Note, I tried using systemd-cat, but this seems obviously better,
405 # and that seemed to have a problem exiting during a systemctl daemon-reload
406 local cmd_name jr_pid s
407 ret=0
408 cmd_name=${1##*/}
409 cmd=$1
410 if [[ $cmd != /* ]]; then
411 cmd=$(which $1)
412 fi
413 journalctl -qn2 -f -u "$cmd_name" &
414 # Guess of time needed to avoid missing initial lines.
415 # .5 was not reliable. 1 was not reliable. 2 was not reliable
416 sleep 3
417 # We kill this in prompt-command for the case that we ctrl-c the
418 # systemd-cat. i dont know any way to trap ctrl-c and still run the
419 # normal action for it. There might be a way, unsure.
420 jr_pid=$!
421 # note, we could have a version that does system --user, but if for example
422 # it does sudo ssh, that will leave a process around that we can't kill
423 # and it will leave the unit hanging around in a failed state needing manual
424 # killing of the process.
425 m s systemd-run --uid $(id -u) --gid $(id -g) \
426 -E SSH_AUTH_SOCK=/run/openssh_agent \
427 --unit "$cmd_name" --wait --collect "$cmd" "${@:2}" || ret=$?
428 # This justs lets the journal output its last line
429 # before the prompt comes up.
430 sleep .5
431 kill $jr_pid &>/dev/null ||:
432 unset jr_pid
433 fg &>/dev/null ||:
434 }
435 # service run, and watch the output
436 srun() {
437 local unit
438 ret=0
439 unit=$1
440 journalctl -qn2 -f -u $unit &
441 systemctl start $unit
442 sleep 2
443 kill $jr_pid &>/dev/null ||:
444 unset jr_pid
445 fg &>/dev/null ||:
446 }
447
448 sm() {
449 local tmp keyhash
450 c /
451 # run latest
452 keyhash=$(s ssh-keygen -lf /root/.ssh/home | awk '{print $2}')
453 tmp=$(s ssh-add -l | awk '$2 == "'$keyhash'"')
454 if [[ ! $tmp ]]; then
455 s ssh-add /root/.ssh/home
456 fi
457 install-my-scripts
458 s jrun switch-mail-host "$@"
459 return $ret
460 }
461
462 # shellcheck disable=SC2120
463 lipush() {
464 # note, i had --delete-excluded, but that deletes all files in --exclude-from on
465 # the remote site, which doesn't make sense, so not sure why i had it.
466 local p a
467 p=(/a/opt/{emacs-debian11{,-nox},mu,emacs} /a/bin /a/exe /a/h /a/c /p/c/machine_specific/vps{,.hosts})
468 a="-ahviSAXPH --specials --devices --delete --relative --exclude-from=/p/c/li-rsync-excludes"
469 ret=0
470 for h in li je bk; do
471 m s rsync "$@" $a ${p[@]} /p/c/machine_specific/$h root@$h.b8.nz:/ || ret=$?
472 # only li is debian11
473 p[0]=/a/opt/emacs-ubuntu20.04
474 p[1]=/a/opt/emacs-ubuntu20.04-nox
475 done
476 m s rsync "$@" -ahviSAXPH root@li.b8.nz:/a/h/proposed-comments/ /a/h/proposed-comments || ret=$?
477 return $ret
478 }
479 bkpush() { # no emacs. for running faster.
480 p=(/a/bin /a/exe /a/h /a/c /p/c/machine_specific/vps{,.hosts})
481 a="-ahviSAXPH --specials --devices --delete --relative --exclude-from=/p/c/li-rsync-excludes"
482 ret=0
483 m rsync "$@" $a ${p[@]} /p/c/machine_specific/bk root@bk.b8.nz:/ || ret=$?
484 return $ret
485 }
486 jepush() { # no emacs. for running faster.
487 p=(/a/bin /a/exe /a/h /a/c /p/c/machine_specific/vps{,.hosts})
488 a="-ahviSAXPH --specials --devices --delete --relative --exclude-from=/p/c/li-rsync-excludes"
489 ret=0
490 m rsync "$@" $a ${p[@]} /p/c/machine_specific/je root@je.b8.nz:/ || ret=$?
491 return $ret
492 }
493
494 bindpush() {
495 dsign iankelling.org expertpathologyreview.com zroe.org amnimal.ninja
496 lipush
497 for h in li bk; do
498 m sl $h <<'EOF'
499 source ~/.bashrc
500 m dnsup
501 EOF
502 done
503 }
504 bindpushb8() {
505 lipush
506 for h in li bk; do
507 m sl $h <<'EOF'
508 source ~/.bashrc
509 m dnsb8
510 EOF
511 done
512 }
513
514 dnsup() {
515 conflink -f
516 m ser reload bind9
517 }
518 dnsb8() {
519 local f=/var/lib/bind/db.b8.nz
520 ser stop bind9
521 sleep 1
522 sudo rm -fv $f.jnl
523 sudo install -m 644 -o bind -g bind /p/c/machine_specific/vps/bind-initial/db.b8.nz $f
524 ser restart bind9
525 }
526 dnsecgen() {
527 # keys generated like this
528 # because of https://ftp.isc.org/isc/dnssec-guide/dnssec-guide.pdf
529 # https://blog.apnic.net/2019/05/23/how-to-deploying-dnssec-with-bind-and-ubuntu-server/
530
531 # key length is longer than that guide because
532 # we are using those at fsf and when old key lengths
533 # become insecure, I want some extra time to update.
534 # dnsecgen (in brc2)
535
536 local zone=$1
537 dnssec-keygen -a RSASHA256 -b 2048 $zone
538 dnssec-keygen -f KSK -a RSASHA256 -b 4096 $zone
539 for f in K$zone.*.key; do
540 # eg Kb8.nz.+008+47995.key tag=47995
541 # in dnsimple, you add the long string from this.
542 # in gandi, you add the long string from the .key file,
543 # then see that the digest matches the ds.
544 echo "tag is the number after DS"
545 dnssec-dsfromkey -a SHA-256 $f
546 done
547 # For b8.nz, we let bind read the keys and sign, and
548 # right now they have root ownership, so let them
549 # get group read.
550 chmod g+r *.private
551 }
552 dsign() {
553 # create .signed file
554 # note: full paths probably not needed.
555 local arg
556 for arg; do
557 local zone=${arg#db.}
558 local dir=/p/c/machine_specific/vps/filesystem/var/lib/bind
559 dnssec-signzone -S -e +31536000 -o $zone -K $dir -d $dir $dir/db.$zone
560 done
561 }
562
563
564 #### begin bitcoin related things
565 btc() {
566 local f=/etc/bitcoin/bitcoin.conf
567 # importprivkey will timeout if using the default of 15 mins.
568 # upped it to 1 hour.
569 bitcoin-cli -rpcclienttimeout=60000 -$(s grep rpcuser= $f) -$(s grep rpcpassword= $f) "$@"
570 }
571 btcusd() { # $1 btc in usd
572 local price
573 price="$(curl -s https://api.coinbase.com/v2/prices/BTC-USD/spot | jq -r .data.amount)"
574 printf "$%s\n" "$price"
575 if [[ $1 ]]; then
576 printf "$%.2f\n" "$(echo "scale=4; $price * $1"| bc -l)"
577 fi
578 }
579 usdbtc() { # $1 usd in btc
580 local price
581 price="$(curl -s https://api.coinbase.com/v2/prices/BTC-USD/spot | jq -r .data.amount)"
582 printf "$%s\n" "$price"
583 if [[ $1 ]]; then
584 # 100 mil satoshi / btc. 8 digits after the 1.
585 printf "%.8f btc\n" "$(echo "scale=10; $1 / $price "| bc -l)"
586 fi
587 }
588 satoshi() { # $1 satoshi in usd
589 local price
590 price="$(curl -s https://api.coinbase.com/v2/prices/BTC-USD/spot | jq -r .data.amount)"
591 price=$(echo "scale=10; $price * 0.00000001"| bc -l)
592 printf "$%f\n" "$price"
593 if [[ $1 ]]; then
594 printf "$%.2f\n" "$(echo "scale=10; $price * $1"| bc -l)"
595 fi
596 }
597 #### end bitcoin related things
598
599
600
601 cbfstool () { /a/opt/coreboot/build/cbfstool "$@"; }
602
603
604 cgpl()
605 {
606 if (($#)); then
607 cp /a/bin/data/COPYING "$@"
608 else
609 cp /a/bin/data/COPYING .
610 fi
611 }
612
613 capache()
614 {
615 if (($#)); then
616 cp /a/bin/data/LICENSE "$@"
617 else
618 cp /a/bin/data/LICENSE .
619 fi
620 }
621
622 chrome() {
623 if type -p chromium &>/dev/null; then
624 cmd=chromium
625 else
626 cd /
627 cmd="schroot -c bullseye chromium"
628 CHROMIUM_FLAGS='--enable-remote-extensions' $cmd &r
629 fi
630 }
631
632
633 # do all tee.
634 # pipe to this, or just type like a shell
635 # todo: test this
636 dat() {
637 tee >(ssh frodo.b8.nz) >(ssh x2) >(ssh tp.b8.nz) >(ssh kw) >(ssh tp.b8.nz)
638 }
639 da() { # do all
640 local host
641 for host in x2 kw tp.b8.nz x3.b8.nz frodo.b8.nz; do
642 ssh $host "$@"
643 done
644 }
645
646
647 debian_pick_mirror () {
648 # netselect-apt finds a fast mirror.
649 # but we need to replace the mirrors ourselves,
650 # because it doesnt do that. best it can do is
651 # output a basic sources file
652 # here we get the server it found, get the main server we use
653 # then substitute all instances of one for the other in the sources file
654 # and backup original to /etc/apt/sources.list-original.
655 # this is idempotent. the only way to identify debian sources is to
656 # note the original server, so we put it in a comment so we can
657 # identify it later.
658 local file
659 file=$(mktemp -d)/f # safe way to get file name without creating one
660 sudo netselect-apt -o "$file" || return 1
661 url=$(grep ^\\w $file | head -n1 | awk '{print $2}')
662 sudo cp -f /etc/apt/sources.list /etc/apt/sources.list-original
663 sudo sed -ri "/http.us.debian.org/ s@( *[^ #]+ +)[^ ]+([^#]+).*@\1$url\2# http.us.debian.org@" /etc/apt/sources.list
664 sudo apt-get update
665 }
666 digme() {
667 digdiff @ns{1,2}.iankelling.org "$@"
668 }
669
670 tsr() { # ts run
671 "$@" |& ts || return $?
672 }
673
674 dup() {
675 local ran_d
676 ran_d=false
677 system-status _
678 case $PS1 in
679 *[\ \]]D\ *)
680 pushd /
681 /b/ds/distro-begin |& ts || return $?
682 /b/ds/distro-end |& ts || return $?
683 popd
684 ran_d=true
685 ;;&
686 *[\ \]]DB\ *)
687 pushd /
688 /b/ds/distro-begin |& ts || return $?
689 popd
690 ran_d=true
691 ;;
692 *[\ \]]DE\ *)
693 pushd /
694 /b/ds/distro-end |& ts || return $?
695 popd
696 ran_d=true
697 ;;&
698 *CONFLINK*)
699 if ! $ran_d; then
700 conflink
701 fi
702 ;;
703 esac
704 system-status _
705 }
706
707 envload() { # load environment from a previous: export > file
708 local file=${1:-$HOME/.${USER}_env}
709 eval "$(export | sed 's/^declare -x/export -n/')"
710 while IFS= read -r line; do
711 # declare -x makes variables local to a function
712 eval ${line/#declare -x/export}
713 done < "$file"
714 }
715
716 failfunc() { asdf a b c; }
717 failfunc2() { failfunc d e f; }
718
719 # one that comes with distros is too old for newer devices
720 fastboot() {
721 /a/opt/android-platform-tools/fastboot "$@";
722 }
723
724 kdecd() { /usr/lib/x86_64-linux-gnu/libexec/kdeconnectd; }
725
726 # List of apps to install/update
727 # Create from existing manually installed apps by doing
728 # fdroidcl update
729 # fdroidcl search -i, then manually removing
730 # automatically installed/preinstalled apps
731
732 #
733 # # my attempt at recovering from boot loop:
734 # # in that case, boot to recovery (volume up, home button, power, let go of power after samsun logo)
735 # # then
736 # mount /dev/block/mmcblk0p12 /data
737 # cd /data
738 # find -iname '*appname*'
739 # rm -rf FOUND_DIRS
740 # usually good enough to just rm -rf /data/app/APPNAME
741 #
742 # currently broken:
743 # # causes replicant to crash
744 # org.quantumbadger.redreader
745 # org.kde.kdeconnect_tp
746
747 # not broke, but wont work without gps
748 #com.zoffcc.applications.zanavi
749 # not broke, but not using atm
750 #com.nutomic.syncthingandroid
751 # # doesn\'t work on replicant
752 #net.sourceforge.opencamera
753 #
754 fdroid_pkgs=(
755 net.mullvad.mullvadvpn
756 org.schabi.newpipe
757 io.github.subhamtyagi.lastlauncher
758 io.anuke.mindustry
759 com.biglybt.android.client
760 de.marmaro.krt.ffupdater
761 me.ccrama.redditslide
762 org.fedorahosted.freeotp
763 at.bitfire.davdroid
764 com.alaskalinuxuser.justnotes
765 com.artifex.mupdf.viewer.app
766 com.danielkim.soundrecorder
767 com.fsck.k9
768 com.ichi2.anki
769 com.jmstudios.redmoon
770 com.jmstudios.chibe
771 org.kde.kdeconnect_tp
772 com.notecryptpro
773 com.termux
774 cz.martykan.forecastie
775 de.danoeh.antennapod
776 de.blinkt.openvpn
777 de.marmaro.krt.ffupdater
778 eu.siacs.conversations
779 free.rm.skytube.oss
780 im.vector.alpha # riot
781 info.papdt.blackblub
782 me.tripsit.tripmobile
783 net.gaast.giggity
784 net.minetest.minetest
785 net.osmand.plus
786 org.isoron.uhabits
787 org.linphone
788 org.gnu.icecat
789 org.smssecure.smssecure
790 org.yaaic
791 sh.ftp.rocketninelabs.meditationassistant.opensource
792 )
793 # https://forum.xda-developers.com/android/software-hacking/wip-selinux-capable-superuser-t3216394
794 # for maru,
795 #me.phh.superuser
796
797 fdup() {
798 local -A installed updated
799 local p
800 # tried putting this in go buildscript cronjob,
801 # but it failed with undefined: os.UserCacheDir. I expect its due to
802 # an environment variable missing, but its easier just to stick it here.
803 m go get -u mvdan.cc/fdroidcl || return 1
804 m fdroidcl update
805 if fdroidcl search -u | grep ^org.fdroid.fdroid; then
806 fdroidcl install org.fdroid.fdroid
807 sleep 5
808 m fdroidcl update
809 fi
810 for p in $(fdroidcl search -i| grep -o "^\S\+"); do
811 installed[$p]=true
812 done
813 for p in $(fdroidcl search -u| grep -o "^\S\+"); do
814 updated[$p]=false
815 done
816 for p in ${fdroid_pkgs[@]}; do
817 if ! ${installed[$p]:-false}; then
818 m fdroidcl install $p
819 # sleeps are just me being paranoid since replicant has a history of crashing when certain apps are installed
820 sleep 5
821 fi
822 done
823 for p in ${!installed[@]}; do
824 if ! ${updated[$p]:-true}; then
825 m fdroidcl install $p
826 sleep 5
827 fi
828 done
829 }
830
831 firefox-default-profile() {
832 key=Default value=1 section=$1
833 file=/p/c/subdir_files/.mozilla/firefox/profiles.ini
834 sed -ri "/^ *$key/d" "$file"
835 sed -ri "/ *\[$section\]/,/^ *\[[^]]+\]/{/^\s*$key[[:space:]=]/d};/ *\[$section\]/a $key=$value" "$file"
836 }
837 fdhome() { #firefox default home profile
838 firefox-default-profile Profile0
839 }
840
841 fdwork() {
842 firefox-default-profile Profile4
843 }
844
845 ff() {
846 if type -P firefox &>/dev/null; then
847 firefox "$@"
848 else
849 iceweasel "$@"
850 fi
851 }
852
853 fn() {
854 firefox -P alt "$@" >/dev/null 2>&1
855 }
856
857
858 fsdiff () {
859 local missing=false
860 local dname="${PWD##*/}"
861 local m="/a/tmp/$dname-missing"
862 local d="/a/tmp/$dname-diff"
863 [[ -e $d ]] && rm "$d"
864 [[ -e $m ]] && rm "$m"
865 local msize=0
866 local fsfile
867 while read -r line; do
868 fsfile="$1${line#.}"
869 if [[ -e "$fsfile" ]]; then
870 md5diff "$line" "$fsfile" && tee -a "/a/tmp/$dname-diff" <<< "$fsfile $line"
871 else
872 missing=true
873 echo "$line" >> "$m"
874 msize=$((msize + 1))
875 fi
876 done < <(find . -type f )
877 if $missing; then
878 echo "$m"
879 (( msize <= 100 )) && cat $m
880 fi
881 }
882 fsdiff-test() {
883 # expected output, with different tmp dirs
884 # /tmp/tmp.HDPbwMqdC9/c/d ./c/d
885 # /a/tmp/tmp.qLDkYxBYPM-missing
886 # ./b
887 cd $(mktemp -d)
888 echo ok > a
889 echo nok > b
890 mkdir c
891 echo ok > c/d
892 local x
893 x=$(mktemp -d)
894 mkdir $x/c
895 echo different > $x/c/d
896 echo ok > $x/a
897 fsdiff $x
898 }
899 rename-test() {
900 # test whether missing files were renamed, generally for use with fsdiff
901 # $1 = fsdiff output file, $2 = directory to compare to. pwd = fsdiff dir
902 # echos non-renamed files
903 local x y found
904 unset sums
905 for x in "$2"/*; do
906 { sums+=( "$(md5sum < "$x")" ) ; } 2>/dev/null
907 done
908 while read -r line; do
909 { missing_sum=$(md5sum < "$line") ; } 2>/dev/null
910 renamed=false
911 for x in "${sums[@]}"; do
912 if [[ $missing_sum == "$x" ]]; then
913 renamed=true
914 break
915 fi
916 done
917 $renamed || echo "$line"
918 done < "$1"
919 return 0
920 }
921
922 feh() {
923 # F = fullscren, z = random, Z = auto zoom
924 command feh -FzZ "$@"
925 }
926
927
928
929 fw() {
930 firefox -P default "$@" >/dev/null 2>&1
931 }
932
933 gitian() {
934 git config user.email ian@iankelling.org
935 }
936
937 # at least in flidas, things rely on gpg being gpg1
938 gpg() {
939 if type -P gpg2 &>/dev/null; then
940 command gpg2 "$@"
941 else
942 command gpg "$@"
943 fi
944 }
945
946 gse() {
947 local email=ian@iankelling.org
948 git send-email --notes "--envelope-sender=<$email>" \
949 --suppress-cc=self "$@"
950 }
951
952 gup() { /a/f/gnulib/build-aux/gnupload "$@"; }
953
954 dejagnu() { /a/opt/dejagnu/dejagnu "$@"; }
955
956 hstatus() {
957 # do git status on published repos.
958 c /a/bin/githtml
959 for x in *; do
960 cd $(readlink -f $x)/..
961 status=$(i status -s) || pwd
962 if [[ $status ]]; then
963 hr
964 echo $x
965 printf "%s\n" "$status"
966 fi
967 cd /a/bin/githtml
968 done
969 }
970
971 # work log
972 wlog() {
973 local day now i
974 now=$(date +%s)
975 for (( i=0; i<60; i++ )); do
976 day=$( date +%F -d @$((now - 86400*i )) )
977 date "+%a %b %d" -d @$((now - 86400*i )) | tr '\n' ' '
978 /a/opt/timetrap/bin/t d -ftotal -s $day -e $day all -m '^w|lunch$'
979 done
980 }
981 to() { t out -a "$@"; }
982 ti() { t in -a "$@"; }
983 tl() {
984 to "$*"
985 t s lunch
986 t in -a "$*"
987 m t out -a $(date +%F.%T -d @$(( $(date -d "$(echo $*|sed 's/[_.]/ /g')" +%s) + 60*45 )) )
988 t s w
989 }
990
991 arbttlog() { arbtt-dump "$@" | grep -v '( )\|Current Desktop' | sed -rn '/^[^ ]/{N;s/^(.{21})([0-9]*)[0-9]{3}m.*\(\*/\1\2/;s/^(.{21})[0-9]*.*\(\*/\1/;s/\n//;p}' ; }
992
993 idea() {
994 /a/opt/idea-IC-163.7743.44/bin/idea.sh "$@" &r
995 }
996
997 ilogs() {
998 ssh root@iankelling.org "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; hr; done"
999 }
1000
1001 ilog() {
1002 chan=${1:-#fsfsys}
1003 # use * instead of -r since that does sorted order
1004 ssh root@iankelling.org "for n in freenode libera; do cd /var/lib/znc/moddata/log/iank/\$n/$chan && hr && for x in *; do echo \$x; sed \"s/^./\${x%log}/\" \$x; hr; done; done" | less +G
1005 }
1006
1007 o() {
1008 if type gio &> /dev/null ; then
1009 gio open "$@"
1010 elif type gvfs-open &> /dev/null ; then
1011 gvfs-open "$@"
1012 else
1013 xdg-open "$@"
1014 fi
1015 # another alternative is run-mailcap
1016 }
1017 ccomp xdg-open o
1018
1019 # jfilter() {
1020 # grep -Evi -e "^(\S+\s+){4}(sudo|sshd|cron)\[\S*:" \
1021 # -e "^(\S+\s+){4}systemd\[\S*: (starting|started) (btrfsmaintstop|dynamicipupdate|spamd dns bug fix cronjob|rss2email)\.*$"
1022 # }
1023 # jtail() {
1024 # journalctl -n 10000 -f "$@" | jfilter
1025 # }
1026 # jr() { journalctl "$@" | jfilter | less ; }
1027 # jrf() { journalctl -n 200 -f "$@" | jfilter; }
1028
1029 jr() { journalctl "$@" ; }
1030 jrf() { journalctl -n 200 -f "$@" ; }
1031
1032
1033 ccomp journalctl jtail jr jrf
1034
1035 kff() { # keyboardio firmware flash
1036 pushd /a/bin/distro-setup/Arduino/Model01-Firmware
1037 yes $'\n' | make flash
1038 popd
1039 }
1040
1041 wgkey() {
1042 local umask_orig name
1043 if (( $# != 1 )); then
1044 e expected 1 arg >&2
1045 return 1
1046 fi
1047 name=$1
1048 umask_orig=$(umask)
1049 umask 0077
1050 wg genkey | tee $name-priv.key | wg pubkey > $name-pub.key
1051 umask $umask_orig
1052 }
1053 wghole() {
1054 if (( $# != 2 )); then
1055 e expected 2 arg of hostname, ip suffix >&2
1056 return 1
1057 fi
1058 local host ipsuf umask_orig
1059 host=$1
1060 ipsuf=$2
1061 mkdir -p /p/c/machine_specific/$host/filesystem/etc/wireguard
1062 cd /p/c/machine_specific/$host/filesystem/etc/wireguard
1063 umask_orig=$(umask)
1064 umask 0077
1065 wg genkey | tee hole-priv.key | wg pubkey > hole-pub.key
1066 cat >wghole.conf <<EOF
1067 [Interface]
1068 # contents hole-priv.key
1069 PrivateKey = $(cat hole-priv.key)
1070 ListenPort = 1194
1071 Address = 10.8.0.$ipsuf/24
1072 # https://dev.to/tangramvision/what-they-don-t-tell-you-about-setting-up-a-wireguard-vpn-1h2g
1073 # ||: makes the systemd service not fail due to the failed command
1074 PostUp = ping -c1 10.8.0.1 ||:
1075
1076 [Peer]
1077 # li. called wgmail on that server
1078 PublicKey = CTFsje45qLAU44AbX71Vo+xFJ6rt7Cu6+vdMGyWjBjU=
1079 AllowedIPs = 10.8.0.0/24
1080 Endpoint = 72.14.176.105:1194
1081 PersistentKeepalive = 25
1082 EOF
1083 umask $umask_orig
1084 # old approach. systemd seems to work fine and cleaner.
1085 rm -f ../network/interfaces.d/wghole
1086 cedit -q $host /p/c/machine_specific/li/filesystem/etc/wireguard/wgmail.conf <<EOF || [[ $? == 1 ]]
1087 [Peer]
1088 PublicKey = $(cat hole-pub.key)
1089 AllowedIPs = 10.8.0.$ipsuf/32
1090 EOF
1091 cd - >/dev/null
1092 }
1093
1094
1095 lom() {
1096 local l base
1097 if [[ $1 == /* ]]; then
1098 base=${1##*/}
1099 if mountpoint -q /mnt/$base; then
1100 return 0
1101 fi
1102 l=$(losetup -j $1 | sed -rn 's/^([^ ]+): .*/\1/p' | head -n1 ||:)
1103 if [[ ! $l ]]; then
1104 l=$(sudo losetup -f)
1105 m sudo losetup $l $1
1106 fi
1107 if ! sudo cryptsetup status /dev/mapper/$base &>/dev/null; then
1108 if ! sudo cryptsetup luksOpen $l $base; then
1109 m sudo losetup -d $l
1110 return 1
1111 fi
1112 fi
1113 m sudo mkdir -p /mnt/$base
1114 m sudo mount /dev/mapper/$base /mnt/$base
1115 m sudo chown $USER:$USER /mnt/$base
1116 else
1117 base=$1
1118 if mountpoint /mnt/$base &>/dev/null; then
1119 m sudo umount /mnt/$base
1120 fi
1121 if sudo cryptsetup status /dev/mapper/$base &>/dev/null; then
1122 if ! m sudo cryptsetup luksClose /dev/mapper/$base; then
1123 echo lom: failed cryptsetup luksClose /dev/mapper/$base
1124 return 1
1125 fi
1126 fi
1127 l=$(losetup -l --noheadings | awk '$6 ~ /\/'$1'$/ {print $1}')
1128 if [[ $l ]]; then
1129 m sudo losetup -d $l
1130 else
1131 echo lom: warning: no loopback device found
1132 fi
1133 fi
1134 }
1135
1136 # mu personality. for original, just run mp. for 2, run mp 2.
1137 # this is partly duplicated in mail-setup
1138 mp() {
1139 local dead=false
1140 for s in {1..5}; do
1141 if ! killall mu; then
1142 dead=true
1143 break
1144 fi
1145 sleep 1
1146 done
1147 if ! $dead; then
1148 echo error: mu not dead
1149 m psg mu
1150 return 1
1151 fi
1152 suf=$1
1153 set -- /m/mucache ~/.cache/mu /m/.mu ~/.config/mu
1154 while (($#)); do
1155 target=$1$suf
1156 f=$2
1157 shift 2
1158 if [[ -e $f && ! -L $f ]]; then
1159 m rm -rf $f
1160 fi
1161 m ln -sf -T $target $f
1162 done
1163 }
1164
1165 # these might need a mu index or something added.
1166 mbenable() {
1167 local mb=$1
1168 dst=/m/4e/$mb
1169 src=/m/md/$mb
1170 [[ -e $src ]] || { echo "src:$src does not exist"; return 1; }
1171 m mv -T $src $dst
1172 m ln -s -T $dst $src
1173 }
1174 mb2enable() {
1175 local mb
1176 for mb; do
1177 dst=/m/4e2/$mb
1178 link=/m/md/$mb
1179 src=/m/md/$mb
1180 if [[ ! -e $src || -L $src ]]; then
1181 src=/m/4e/$mb
1182 fi
1183 [[ -e $src ]] || { echo "src:$src does not exist"; return 1; }
1184 m mv -T $src $dst
1185 m ln -sf -T $dst $link
1186 done
1187 }
1188 mbdisable() {
1189 local mb=$1
1190 dst=/m/md/$mb
1191 src=/m/4e/$mb
1192 set -x
1193 [[ -e $src ]] || { set +x; return 1; }
1194 if [[ -L $dst ]]; then rm $dst; fi
1195 mv -T $src $dst
1196 set +x
1197 }
1198
1199
1200 mdt() {
1201 markdown "$1" >/tmp/mdtest.html
1202 firefox /tmp/mdtest.html
1203 }
1204
1205 mo() { xset dpms force off; } # monitor off
1206
1207 mpvd() {
1208 mpv --profile=d "$@";
1209 }
1210 mpvs() {
1211 mpv --profile=s "$@";
1212 }
1213
1214 myirc() {
1215 if [[ ! $1 ]]; then
1216 set -- fsf-office
1217 fi
1218 local d1 d2
1219 d=( /var/lib/znc/moddata/log/iank/{freenode,libera} )
1220 # use * instead of -r since that does sorted order
1221 ssh root@iankelling.org "for f in ${d[@]}; do cd \$f/#$1; grep '\<iank.*' *; done" | cut --complement -c12-16
1222 }
1223 mypidgin() {
1224 c /p/c/.purple/logs/jabber/iank@fsf.org/office@conference.fsf.org.chat
1225 for x in *.html; do html2text -o ${x%.html}.txt $x; done;
1226 grep -A1 ') iank:' *.txt | sed -r 's/^(.{10})[^ ]*\.txt:\(?([^ ]*)[[:space:]](..). iank:/\1_\2_\3/;s/^[^ ]*\.txt-//;/^--$/d;s/^[^ ]*\.txt:\((.{2}).(.{2}).(.{4}) (.{8}) (.{2})\)?/\3-\1-\2_\4_\5/' | sed -n 'x;1d;0~2{G;s/\n/ /;p};${x;p}'
1227 }
1228 allmyirc() {
1229 local d
1230 d=/var/lib/znc/moddata/log/iank/freenode
1231 ssh root@iankelling.org "cd $d; find . -mtime -60 -type f -exec grep '\<iank.*' {} +" | sed -r 's,^..([^/]*)/(.{11})(.{5})(.{8}).,\2\4 \1,' | sort
1232 }
1233
1234 mygajim() {
1235 local now time time_sec time_pretty
1236 now=$(date +%s)
1237 sqlite3 -separator ' ' /p/c/subdir_files/.local/share/gajim/logs.db "select time, message from logs where contact_name = 'iank' and jid_id = 17;" | while read -r time l; do
1238 case $time in
1239 16*) : ;;
1240 *) continue ;;
1241 esac
1242 if ! time_pretty=$(date +%F.%R -d @$time); then
1243 echo bad time: $time
1244 return 1
1245 fi
1246 echo $time_pretty "$l"
1247 time_sec=${time%%.*}
1248 # only look at the last 18 days. generally just use this for timesheet.
1249 if (( time_sec < now - 60 * 60 * 24 * 18 )); then break; fi
1250 done
1251 }
1252
1253 gajlogs() {
1254 sqlite3 -separator ' ' /p/c/subdir_files/.local/share/gajim/logs.db "select time, message from logs" | less
1255 }
1256
1257 net-dev-info() {
1258 e "lspci -nnk|gr -iA2 net"
1259 lspci -nnk|gr -iA2 net
1260 hr
1261 e "s lshw -C network"
1262 hr
1263 sudo lshw -C network
1264 }
1265
1266 nk() {
1267 ser stop NetworkManager
1268 ser disable NetworkManager
1269 ser stop NetworkManager-wait-online.service
1270 ser disable NetworkManager-wait-online.service
1271 ser stop dnsmasq
1272 sudo resolvconf -d NetworkManager
1273 # ser start dnsmasq
1274 sudo ifup br0
1275 }
1276 ngo() {
1277 sudo ifdown br0
1278 ser start NetworkManager
1279 sleep 4
1280 sudo nmtui-connect
1281 }
1282
1283 otp() {
1284 oathtool --totp -b "$*" | xclip -selection clipboard
1285 }
1286 j() {
1287 "$@" |& pee "xclip -r -selection clipboard"
1288 }
1289
1290
1291 pakaraoke() {
1292 # from http://askubuntu.com/questions/456021/remove-vocals-from-mp3-and-get-only-instrumentals
1293 pactl load-module module-ladspa-sink sink_name=Karaoke master=alsa_output.usb-Audioengine_Audioengine_D1-00.analog-stereo plugin=karaoke_1409 label=karaoke control=-30
1294 }
1295
1296 pfind() { #find *$1* in $PATH
1297 [[ $# != 1 ]] && { echo requires 1 argument; return 1; }
1298 local pathArray
1299 IFS=: pathArray=($PATH); unset IFS
1300 find "${pathArray[@]}" -iname "*$1*"
1301 }
1302
1303 pick-trash() {
1304 # trash-restore lists everything that has been trashed at or below CWD
1305 # This picks out files just in CWD, not subdirectories,
1306 # which also match grep $1, usually use $1 for a time string
1307 # which you get from running restore-trash once first
1308 local name x ask
1309 local nth=1
1310 # last condition is to not ask again for ones we skipped
1311 while name="$( echo | restore-trash | gr "$PWD/[^/]\+$" | gr "$1" )" \
1312 && [[ $name ]] && (( $(wc -l <<<"$name") >= nth )); do
1313 name="$(echo "$name" | head -n $nth | tail -n 1 )"
1314 read -r -p "$name [Y/n] " ask
1315 if [[ ! $ask || $ask == [Yy] ]]; then
1316 x=$( echo "$name" | gr -o "^\s*[0-9]*" )
1317 echo $x | restore-trash > /dev/null
1318 elif [[ $ask == [Nn] ]]; then
1319 nth=$((nth+1))
1320 else
1321 return
1322 fi
1323 done
1324 }
1325
1326
1327 pub() {
1328 rld /a/h/_site/ li:/var/www/iankelling.org/html
1329 }
1330
1331
1332 pumpa() {
1333 # fixes the menu bar in xmonad. this won\'t be needed when xmonad
1334 # packages catches up on some changes in future (this is written in
1335 # 4/2017)
1336 #
1337 # geekosaur: so youll want to upgrade to xmonad 0.13 or else use a
1338 # locally modified XMonad.Hooks.ManageDocks that doesnt set the
1339 # work area; turns out it\'s impossible to set correctly if you are
1340 # not a fully EWMH compliant desktop environment
1341 #
1342 # geekosaur: chrome shows one failure mode, qt/kde another, other
1343 # gtk apps a third, ... I came up with a setting that works for me
1344 # locally but apparently doesnt work for others, so we joined the
1345 # other tiling window managers in giving up on setting it at all
1346 #
1347 xprop -root -remove _NET_WORKAREA
1348 command pumpa & r
1349 }
1350
1351 # reviewboard, used at my old job
1352 #rbpipe() { rbt post -o --diff-filename=- "$@"; }
1353 #rbp() { rbt post -o "$@"; }
1354
1355 rebr() {
1356 sudo ifdown br0
1357 sudo ifup br0
1358 }
1359
1360
1361 # only run on MAIL_HOST. simpler to keep this on one system.
1362 r2eadd() { # usage: name url
1363 # initial setup of rss2email:
1364 # r2e new r2e@iankelling.org
1365 # that initializes files, and sets default email.
1366 # symlink to the config doesnt work, so I copied it to /p/c
1367 # and then use cli option to specify explicit path.
1368 # Only option changed from default config is to set
1369 # force-from = True
1370 #
1371 # or else for a few feeds, the from address is set by the feed, and
1372 # if I fail delivery, then I send a bounce message to that from
1373 # address, which makes me be a spammer.
1374
1375 r2e add $1 "$2" $1@r2e.iankelling.org
1376 # get up to date and dont send old entries now:
1377 r2e run --no-send $1
1378 }
1379 r2e() { command r2e -d /p/c/rss2email.json -c /p/c/rss2email.cfg "$@"; }
1380
1381 rspicy() { # usage: HOST DOMAIN
1382 # connect to spice vm remote host. use vspicy for local host
1383 local port
1384 # shellcheck disable=SC2087
1385 port=$(ssh $1<<EOF
1386 sudo virsh dumpxml $2|grep "<graphics.*type='spice'" | \
1387 sed -rn "s/.*port='([0-9]+).*/\1/p"
1388 EOF
1389 )
1390 if [[ $port ]]; then
1391 spicy -h $1 -p $port
1392 else
1393 echo "error: no port found. check that the domain is running."
1394 fi
1395 }
1396
1397
1398 scssl() {
1399 # s gem install scss-lint
1400 pushd /a/opt/thoughtbot-guides
1401 git pull --stat
1402 popd
1403 scss-lint -c /a/opt/thoughtbot-guides/style/sass/.scss-lint.yml "$@"
1404 }
1405
1406 skbrc() {
1407 sk -e 2120,245 /b/ds/brc /b/ds/brc2
1408 }
1409
1410 skaraoke() {
1411 local tmp out
1412 out=${2:-${1%.*}.sh}
1413 tmp=$(mktemp -d)
1414 script -t -c "mpv --no-config --no-resume-playback --no-terminal --no-audio-display '$1'" $tmp/typescript 2>$tmp/timing
1415 # todo, the current sleep seems pretty good, but it
1416 # would be nice to have an empirical measurement, or
1417 # some better wait to sync up.
1418 #
1419 # note: --loop-file=no prevents it from hanging if you have that
1420 # set to inf the mpv config.
1421 # --loop=no prevents it from exit code 3 due to stdin if you
1422 # had it set to inf in mpv config.
1423 #
1424 # args go to mpv, for example --volume=80, 50%
1425 cat >$out <<EOFOUTER
1426 #!/bin/bash
1427 trap "trap - TERM && kill 0" INT TERM ERR; set -e
1428 ( sleep .2; scriptreplay <( cat <<'EOF'
1429 $(cat $tmp/timing)
1430 EOF
1431 ) <( cat <<'EOF'
1432 $(cat $tmp/typescript)
1433 EOF
1434 ))&
1435 base64 -d - <<'EOF'| mpv --loop=no --loop-file=no --no-terminal --no-audio-display "\$@" -
1436 $(base64 "$1")
1437 EOF
1438 kill 0
1439 EOFOUTER
1440 rm -r $tmp
1441 chmod +x $out
1442 }
1443
1444 smeld() { # ssh meld usage host1 host2 file
1445 meld <(ssh $1 cat $3) <(ssh $2 cat $3)
1446 }
1447
1448 spd() {
1449 PATH=/usr/local/spdhackfix:$PATH command spd "$@"
1450 }
1451
1452 spend() {
1453 sudo systemctl suspend
1454 }
1455
1456 spamf() { # spamtest on FILE
1457 local spamcpre spamdpid
1458
1459 if (( $# != 1 )); then
1460 e spamtest error: expected 1 arg, filename >&2
1461 return 1
1462 fi
1463
1464 spamdpid=$(systemctl status spamassassin| sed -n '/^ *Main PID:/s/[^0-9]//gp')
1465 spamcpre="nsenter -t $spamdpid -n -m"
1466 s $spamcpre sudo -u Debian-exim spamassassin -t --cf='score PYZOR_CHECK 0' <"$1"
1467 }
1468
1469
1470 # mail related
1471 testmail() {
1472 declare -gi _seq; _seq+=1
1473 echo "test body" | m mail -s "test mail from $HOSTNAME, $_seq" "${@:-root@localhost}"
1474 # for testing to send from an external address, you can do for example
1475 # -fian@iank.bid -aFrom:ian@iank.bid web-6fnbs@mail-tester.com
1476 # note in exim, you can retry a deferred message
1477 # s exim -M MSG_ID
1478 # MSG_ID is in /var/log/exim4/mainlog, looks like 1ccdnD-0001nh-EN
1479 }
1480
1481 # to test sieve, use below command. for fsf mail, see offlineimap-sync script
1482 # make modifications, then copy to live file, use -eW to actually modify mailbox
1483 #
1484 # Another option is to use sieve-test SCRIPT MAIL_FILE. note,
1485 # sieve-test doesnt know about envelopes, Im not sure if sieve-filter does.
1486
1487 # sieve with output filter. arg is mailbox, like INBOX.
1488 # This depends on dovecot conf, notably mail_location in /etc/dovecot/conf.d/10-mail.conf
1489
1490 # always run this first, edit the test files, then run the following
1491 testsieve() {
1492 sieve-filter ~/sieve/maintest.sieve ${1:-INBOX} delete 2> >(head; tail) >/tmp/testsieve.log && sed -rn '/^Performed actions:/,/^[^ ]/{/^ /p}' /tmp/testsieve.log | sort | uniq -c
1493 }
1494 runsieve() {
1495 c ~/sieve; cp personal{test,}.sieve; cp lists{test,}.sieve; cp personalend{test,}.sieve
1496 sieve-filter -eWv ~/sieve/maintest.sieve ${1:-INBOX} delete &> /tmp/testsieve.log
1497 sed -r '/^info: filtering:/{h;d};/^info: msgid=$/N;/^info: msgid=.*left message in mailbox [^ ]+$/d;/^info: msgid=/{H;g};/^info: message kept in source mailbox.$/d' /tmp/testsieve.log
1498 }
1499
1500 # usage:
1501 # alertme SUBJECT
1502 # printf "subject\nbody\n" | alertme
1503 alertme() {
1504 if [[ -t 0 ]]; then
1505 exim -t <<EOF
1506 From: alertme@b8.nz
1507 To: alerts@iankelling.org
1508 Subject: $*
1509 EOF
1510 else
1511 read sub
1512 { cat <<EOF
1513 From: alertme@b8.nz
1514 To: alerts@iankelling.org
1515 Subject: $sub
1516
1517 EOF
1518 cat
1519 } | exim -t
1520 fi
1521 }
1522 daylertme() {
1523 if [[ -t 0 ]]; then
1524 exim -t <<EOF
1525 From: alertme@b8.nz
1526 To: daylert@iankelling.org
1527 Subject: $*
1528 EOF
1529 else
1530 read sub
1531 { cat <<EOF
1532 From: alertme@b8.nz
1533 To: daylert@iankelling.org
1534 Subject: $sub
1535
1536 EOF
1537 cat
1538 } | exim -t
1539 fi
1540 }
1541
1542 # alert when a page goes live. not urgent.
1543 alert200() {
1544 url="$1"
1545 tmpdir="$(mktemp -d)"
1546 cd $tmpdir
1547 while true; do
1548 if torsocks wget -q "$url"; then
1549 alertme $tmpdir
1550 fi
1551 sleep $(( 600 + RANDOM % 300 ))
1552 done
1553 }
1554
1555
1556 # mail related
1557 testexim() {
1558 # testmail above calls sendmail, which is a link to exim/postfix.
1559 # its docs dont say a way of adding an argument
1560 # to sendmail to turn on debug output. We could make a wrapper, but
1561 # that is a pain. Exim debug args are documented here:
1562 # http://www.exim.org/exim-html-current/doc/html/spec_html/ch-the_exim_command_line.html
1563 #
1564 # http://www.exim.org/exim-html-current/doc/html/spec_html/ch-building_and_installing_exim.html
1565 # note, for exim daemon, you can turn on debug options by
1566 # adding -d, etc to COMMONOPTIONS in
1567 # /etc/default/exim4
1568 #
1569 # to specify recipients other than those in to, cc, bcc, you can use the cli args, eg:
1570 # exim -t 'test@zroe.org, t2@zroe.org' <<'EOF'
1571 #
1572 # -t = get recipient from header
1573 exim -d -t <<'EOF'
1574 From: i@dmarctest.b8.nz
1575 To: mailman@dev.fsf.org
1576 Subject: test2
1577 Reply-to: rtest@iankelling.org
1578
1579 This is a test message.
1580 EOF
1581 }
1582
1583 # toggle keyboard
1584 tk() {
1585 # based on
1586 # https://askubuntu.com/questions/160945/is-there-a-way-to-disable-a-laptops-internal-keyboard
1587 id=$(xinput --list --id-only 'AT Translated Set 2 keyboard')
1588 if xinput list | grep -F '∼ AT Translated Set 2 keyboard' &>/dev/null; then
1589 echo enabling keyboard
1590 # find the first slave keyboard number, they are all the same in my output.
1591 # if they werent, worst case we would need to save the slave number somewhere
1592 # when it got disabled.
1593 slave=$(xinput list | sed -n 's/.*slave \+keyboard (\([0-9]*\)).*/\1/p' | head -n1)
1594 xinput reattach $id $slave
1595 else
1596 xinput float $id
1597 fi
1598 }
1599
1600 tm() {
1601 # timer in minutes
1602 # --no-config
1603 (sleep $(calc "$* * 60") && mpv --no-config --volume 50 /a/bin/data/alarm.mp3) > /dev/null 2>&1 &
1604 }
1605
1606 trg() { transmission-remote-gtk & r; }
1607 trc() {
1608 # example, set global upload limit to 100 kilobytes:
1609 # trc -u 100
1610 TR_AUTH=":$(jq -r .profiles[0].password ~/.config/transmission-remote-gtk/config.json)" transmission-remote transmission.lan -ne "$@"
1611 }
1612
1613 trysleep() {
1614 retries="$1"
1615 sleepsecs="$2"
1616 shift 2
1617 for (( i=0; i < retries - 1; i++ )); do
1618 if "$@"; then
1619 return 0
1620 fi
1621 sleep $sleepsecs
1622 done
1623 "$@"
1624 }
1625
1626
1627 tu() {
1628 local s
1629 if [[ -e $1 && ! -w $1 || ! -w $(dirname "$1") ]]; then
1630 s=s;
1631 fi
1632 # full path for using in some initial setup steps
1633 $s /a/exe/teeu "$@"
1634 }
1635
1636 enn() {
1637 local ecmd pid
1638
1639 ecmd="/usr/sbin/exim4 -C /etc/exim4/my.conf"
1640 if ip a show veth1-mail &>/dev/null; then
1641 s $ecmd "$@"
1642 return
1643 fi
1644 pid=$(pgrep -f "/usr/sbin/exim4 -bd -q30m -C /etc/exim4/my.conf"|h1)
1645 m s nsenter -t $pid -n -m $ecmd "$@"
1646 }
1647
1648 sdnbash() { # systemd namespace bash
1649 local unit=$1
1650 m sudo nsenter -t $(systemctl show --property MainPID --value $unit) -n -m sudo -u $USER -i bash
1651 }
1652
1653 mailnnbash() {
1654 m sudo nsenter -t $(systemctl show --property MainPID --value mailnn) -n -m sudo -u $USER -i bash
1655 }
1656
1657 mailvpnbash() {
1658 m sudo nsenter -t $(pgrep -f "/usr/sbin/openvpn .* --config /etc/openvpn/.*mail.conf") -n -m sudo -u $USER -i bash
1659 }
1660 eximbash() {
1661 local pid
1662 pid=$(pgrep -f "/usr/sbin/exim4 -bd -q30m -C /etc/exim4/my.conf"|h1)
1663 if [[ ! $pid ]]; then
1664 echo "eximbash: failed to find exim pid. systemctl -n 30 status exim4:"
1665 systemctl status exim4
1666 fi
1667 m sudo nsenter -t $pid -n -m
1668 }
1669 spamnn() {
1670 local spamdpid
1671 spamdpid=$(systemctl show --property MainPID --value spamassassin)
1672 m sudo nsenter -t $spamdpid -n -m sudo -u Debian-exim spamassassin "$@"
1673 }
1674 unboundbash() {
1675 m sudo nsenter -t $(systemctl status unbound| sed -n '/^ *Main PID:/s/[^0-9]//gp') -n -m sudo -u $USER -i bash
1676 }
1677
1678 mailnncheck() {
1679 local p pid ns mailnn
1680 # mailvpn would belong on the list if using openvpn
1681 for p in mailnn unbound dovecot spamassassin exim4 radicale; do
1682 case $p in
1683 exim4|radicale)
1684 pid=$(ps -eo pid,cgroup | grep /system.slice/$p.service | awk '{print $1}')
1685 ;;
1686 *)
1687 pid=$(s systemctl show --property MainPID --value $p)
1688 ;;
1689 esac
1690 echo p=$p pid=$pid
1691 if [[ ! $pid ]]; then
1692 echo failed to find pid for $p
1693 continue
1694 fi
1695 if ! ns=$(s readlink /proc/$pid/ns/net); then
1696 echo failed to find ns for $p pid=$pid
1697 continue
1698 fi
1699 if [[ $mailnn ]]; then
1700 if [[ $ns != "$mailnn" ]]; then
1701 echo "$p ns $ns != $mailnn"
1702 fi
1703 else
1704 mailnn=$ns
1705 fi
1706 done
1707
1708 }
1709
1710
1711 vpncmd() {
1712 m sudo -E env "PATH=$PATH" nsenter -t $(pgrep -f "/usr/sbin/openvpn .* --config /etc/openvpn/.*client.conf") -n -m "$@"
1713 }
1714 vpnf() {
1715 vpncmd sudo -E -u iank env "PATH=$PATH" abrowser -no-remote -P vpn & r
1716 }
1717 vpn2f() {
1718 vpncmd sudo -u iank env "PATH=$PATH" abrowser -no-remote -P vpn2 & r
1719 }
1720
1721 vpni() {
1722 vpncmd sudo -u iank env "PATH=$PATH" "$@"
1723 }
1724 vpnbash() {
1725 vpncmd bash
1726 }
1727
1728
1729 vpn() {
1730 if [[ -e /lib/systemd/system/openvpn-client@.service ]]; then
1731 local vpn_service=openvpn-client
1732 else
1733 local vpn_service=openvpn
1734 fi
1735
1736 [[ $1 ]] || { echo need arg; return 1; }
1737 journalctl --unit=$vpn_service@$1 -f -n0 &
1738 # sometimes the journal doesnt open until after the vpn output
1739 # has happened. hoping this fixes that.
1740 sleep 1
1741 sudo systemctl start $vpn_service@$1
1742 # sometimes the ask-password agent does not work and needs a delay.
1743 sleep .5
1744 # https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=779240
1745 # noticed around 8-2017 after update from around stretch release
1746 # on debian testing, even though the bug is much older.
1747 sudo systemd-tty-ask-password-agent
1748 }
1749
1750 fixu() {
1751 ls -lad /run/user/1000
1752 s chmod 700 /run/user/1000; s chown iank.iank /run/user/1000
1753 }
1754
1755 # systemctl is-enabled / status / cat says nothing, instead theres
1756 # some obscure symlink. paths copied from man systemd.unit.
1757 # possibly also usefull, but incomplete, doesnt show units not loaded in memory:
1758 # seru list-dependencies --reverse --all UNIT
1759 sysd-deps() {
1760 local f
1761 local -a dirs search
1762 ngset
1763
1764 case $1 in
1765 u)
1766 search=(
1767 ~/.config/systemd/user.control/*
1768 $XDG_RUNTIME_DIR/systemd/user.control/*
1769 $XDG_RUNTIME_DIR/systemd/transient/*
1770 $XDG_RUNTIME_DIR/systemd/generator.early/*
1771 ~/.config/systemd/user/*
1772 /etc/systemd/user/*
1773 $XDG_RUNTIME_DIR/systemd/user/*
1774 /run/systemd/user/*
1775 $XDG_RUNTIME_DIR/systemd/generator/*
1776 ~/.local/share/systemd/user/*
1777 /usr/lib/systemd/user/*
1778 $XDG_RUNTIME_DIR/systemd/generator.late/*
1779 )
1780 ;;
1781 *)
1782 search=(
1783 /etc/systemd/system.control/*
1784 /run/systemd/system.control/*
1785 /run/systemd/transient/*
1786 /run/systemd/generator.early/*
1787 /etc/systemd/system/*
1788 /etc/systemd/systemd.attached/*
1789 /run/systemd/system/*
1790 /run/systemd/systemd.attached/*
1791 /run/systemd/generator/*
1792 /lib/systemd/system/*
1793 /run/systemd/generator.late/*
1794 )
1795 ;;
1796 esac
1797 for f in "${search[@]}"; do
1798 [[ -d $f ]] || continue
1799 case $f in
1800 *.requires|*.wants)
1801 dirs+=("$f")
1802 ;;
1803 esac
1804 done
1805 # dirs is just so we write out the directory names, ls does it when there is 2 or more dirs.
1806 case ${#dirs[@]} in
1807 1)
1808 echo "${dirs[0]}:"
1809 ll "${dirs[@]}"
1810 ;;
1811 0) : ;;
1812 *)
1813 ll "${dirs[@]}"
1814 ;;
1815 esac
1816 ngreset
1817 }
1818
1819 fixvpndns() {
1820 local link istls
1821 read _ link _ istls < <(resolvectl dnsovertls tunfsf)
1822 case $istls in
1823 yes|no) : ;;
1824 *) echo fixvpndns error: unexpected istls value: $istls >&2; return 1 ;;
1825 esac
1826 s busctl call org.freedesktop.resolve1 /org/freedesktop/resolve1 org.freedesktop.resolve1.Manager SetLinkDNSOverTLS is $link no
1827 }
1828
1829 vpnoff() {
1830 [[ $1 ]] || { echo need arg; return 1; }
1831 if [[ -e /lib/systemd/system/openvpn-client@.service ]]; then
1832 local vpn_service=openvpn-client
1833 else
1834 local vpn_service=openvpn
1835 fi
1836 sudo systemctl stop $vpn_service@$1
1837 }
1838 vpnoffc() { # vpn off client
1839 ser stop openvpn-client-tr@client
1840 }
1841 vpnc() {
1842 ser start openvpn-client-tr@client
1843 }
1844
1845
1846 vspicy() { # usage: VIRSH_DOMAIN
1847 # connect to vms made with virt-install
1848 spicy -p $(sudo virsh dumpxml "$1"|grep "<graphics.*type='spice'"|\
1849 sed -r "s/.*port='([0-9]+).*/\1/")
1850 }
1851
1852 wian() {
1853 cat-new-files /m/4e/INBOX/new
1854 }
1855
1856 wtr() { curl wttr.in/boston; }
1857
1858 xevkb() { xev -event keyboard; }
1859
1860 # * misc stuff
1861
1862 vrun() {
1863 printf "running: %s\n" "$*"
1864 "$@"
1865 }
1866
1867 f=/a/f/ansible-configs/files/common/etc/fsf-workstation-bashrc.sh
1868 if [[ -e $f ]]; then
1869 # shellcheck disable=SC1090
1870 source $f
1871 fi
1872
1873
1874
1875
1876 reset-konsole() {
1877 # we also have a file in /a/c/...konsole...
1878 local f=$HOME/.config/konsolerc
1879 setini DefaultProfile profileian.profile "Desktop Entry" $f
1880 setini Favorites profileian.profile "Favorite Profiles" $f
1881 setini ShowMenuBarByDefault false KonsoleWindow $f
1882 setini TabBarPosition Top TabBar $f
1883 }
1884
1885 reset-sakura() {
1886 while read -r k v; do
1887 # shellcheck disable=SC2154
1888 setini $k $v sakura /a/c/subdir_files/.config/sakura/sakura.conf
1889 done <<'EOF'
1890 colorset1_back rgb(33,37,39)
1891 less_questions true
1892 audible_bell No
1893 visible_bell No
1894 disable_numbered_tabswitch true
1895 scroll_lines 10000000
1896 scrollbar true
1897 EOF
1898 }
1899
1900 reset-xscreensaver() {
1901 # except for spash, i set these by setting gui options in
1902 # xscreensaver-command -demo
1903 # then finding the corresponding option in .xscreensaver
1904 # spash, i happened to notice in .xscreensaver
1905 #
1906 # dpmsOff, monitor doesnt come back on using old free software supported nvidia card
1907 cat > /home/iank/.xscreensaver <<'EOF'
1908 mode: blank
1909 dpmsEnabled: True
1910 dpmsStandby: 0:07:00
1911 dpmsSuspend: 0:08:00
1912 dpmsOff: 0:00:00
1913 timeout: 0:05:00
1914 lock: True
1915 lockTimeout: 0:06:00
1916 splash: False
1917 EOF
1918
1919 }
1920
1921
1922 # * stuff that makes sense to be at the end
1923 if [[ "$SUDOD" ]]; then
1924 # allow failure, for example if we are sudoing into a user with diffferent/lesser permissions.
1925 cd "$SUDOD" ||:
1926 unset SUDOD
1927 elif [[ -d /a ]] && [[ $PWD == "$HOME" ]] && [[ $- == *i* ]]; then
1928 cd /a
1929 fi
1930
1931
1932
1933
1934 # for mitmproxy to get a newer python.
1935 # commented until i want to use it because it
1936 # noticably slows bash startup
1937 #
1938
1939 mypyenvinit () {
1940 if [[ $EUID == 0 || ! -e ~/.pyenv/bin ]]; then
1941 echo "error: dont be root. make sure pyenv is installed"
1942 return 1
1943 fi
1944 export PATH="$HOME/.pyenv/bin:$PATH"
1945 eval "$(pyenv init -)"
1946 eval "$(pyenv virtualenv-init -)"
1947 }
1948
1949
1950 export GOPATH=$HOME/go
1951 path-add $GOPATH/bin
1952 path-add /usr/local/go/bin
1953
1954 # I have the git repo and a release. either one should work.
1955 # I have both because I was trying to solve an issue that
1956 # turned out to be unrelated.
1957 # ARDUINO_PATH=/a/opt/Arduino/build/linux/work
1958 export ARDUINO_PATH=/a/opt/arduino-1.8.15
1959 export KALEIDOSCOPE_DIR=/a/opt/Kaleidoscope
1960
1961 # They want to be added to the start, but i think
1962 # that should be avoided unless we really need it.
1963 path-add --end ~/.npm-global
1964
1965
1966 path-add --end $HOME/.cargo/bin
1967
1968 if type -P rg &>/dev/null; then
1969 # --no-messages because of annoying errors on broken symlinks
1970 rg() { command rg --no-messages -L -i -M 300 --no-ignore "$@" || return $?; }
1971 #fails if not exist. ignore
1972 complete -r rg 2>/dev/null ||:
1973 else
1974 alias rg=grr
1975 fi
1976
1977
1978
1979 # taken from default changes to bashrc and bash_profile
1980 path-add --end --ifexists $HOME/.rvm/bin
1981 # also had ruby bin dir, but moved that to environment.sh
1982 # so its included in overall env
1983
1984
1985 export BASEFILE_DIR=/a/bin/fai-basefiles
1986
1987 #export ANDROID_HOME=/a/opt/android-home
1988 # https://f-droid.org/en/docs/Installing_the_Server_and_Repo_Tools/
1989 #export USE_SDK_WRAPPER=yes
1990 #PATH=$PATH:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools
1991
1992 # didnt get drush working, if I did, this seems like the
1993 # only good thing to include for it.
1994 # Include Drush completion.
1995 # if [ -f "/home/ian/.drush/drush.complete.sh" ] ; then
1996 # source /home/ian/.drush/drush.complete.sh
1997 # fi
1998
1999
2000 # best practice
2001 unset IFS
2002
2003 # https://wiki.archlinux.org/index.php/Xinitrc#Autostart_X_at_login
2004 # i added an extra condition as gentoo xorg guide says depending on
2005 # $DISPLAY is fragile.
2006 if [[ ! $DISPLAY && $XDG_VTNR == 1 ]] && shopt -q login_shell && isarch; then
2007 exec startx
2008 fi
2009
2010
2011 # ensure no bad programs appending to this file will have an affect
2012 return 0