fixes, prometheus, lots of stuff
[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 m sudo nsenter -t $(pgrep -f "/usr/sbin/exim4 -bd -q30m -C /etc/exim4/my.conf"|h1) -n -m sudo -u $USER -i bash
1662 }
1663 spamnn() {
1664 local spamdpid
1665 spamdpid=$(systemctl show --property MainPID --value spamassassin)
1666 m sudo nsenter -t $spamdpid -n -m sudo -u Debian-exim spamassassin "$@"
1667 }
1668 unboundbash() {
1669 m sudo nsenter -t $(systemctl status unbound| sed -n '/^ *Main PID:/s/[^0-9]//gp') -n -m sudo -u $USER -i bash
1670 }
1671
1672 mailnncheck() {
1673 local p pid ns mailnn
1674 # mailvpn would belong on the list if using openvpn
1675 for p in mailnn unbound dovecot spamassassin exim4 radicale; do
1676 case $p in
1677 exim4|radicale)
1678 pid=$(ps -eo pid,cgroup | grep /system.slice/$p.service | awk '{print $1}')
1679 ;;
1680 *)
1681 pid=$(s systemctl show --property MainPID --value $p)
1682 ;;
1683 esac
1684 echo p=$p pid=$pid
1685 if [[ ! $pid ]]; then
1686 echo failed to find pid for $p
1687 continue
1688 fi
1689 if ! ns=$(s readlink /proc/$pid/ns/net); then
1690 echo failed to find ns for $p pid=$pid
1691 continue
1692 fi
1693 if [[ $mailnn ]]; then
1694 if [[ $ns != "$mailnn" ]]; then
1695 echo "$p ns $ns != $mailnn"
1696 fi
1697 else
1698 mailnn=$ns
1699 fi
1700 done
1701
1702 }
1703
1704
1705 vpncmd() {
1706 m sudo -E env "PATH=$PATH" nsenter -t $(pgrep -f "/usr/sbin/openvpn .* --config /etc/openvpn/.*client.conf") -n -m "$@"
1707 }
1708 vpnf() {
1709 vpncmd sudo -E -u iank env "PATH=$PATH" abrowser -no-remote -P vpn & r
1710 }
1711 vpn2f() {
1712 vpncmd sudo -u iank env "PATH=$PATH" abrowser -no-remote -P vpn2 & r
1713 }
1714
1715 vpni() {
1716 vpncmd sudo -u iank env "PATH=$PATH" "$@"
1717 }
1718 vpnbash() {
1719 vpncmd bash
1720 }
1721
1722
1723 vpn() {
1724 if [[ -e /lib/systemd/system/openvpn-client@.service ]]; then
1725 local vpn_service=openvpn-client
1726 else
1727 local vpn_service=openvpn
1728 fi
1729
1730 [[ $1 ]] || { echo need arg; return 1; }
1731 journalctl --unit=$vpn_service@$1 -f -n0 &
1732 # sometimes the journal doesnt open until after the vpn output
1733 # has happened. hoping this fixes that.
1734 sleep 1
1735 sudo systemctl start $vpn_service@$1
1736 # sometimes the ask-password agent does not work and needs a delay.
1737 sleep .5
1738 # https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=779240
1739 # noticed around 8-2017 after update from around stretch release
1740 # on debian testing, even though the bug is much older.
1741 sudo systemd-tty-ask-password-agent
1742 }
1743
1744 ufix() {
1745 ls -lad /run/user/1000
1746 s chmod 700 /run/user/1000; s chown iank.iank /run/user/1000
1747 }
1748
1749 # systemctl is-enabled / status / cat says nothing, instead theres
1750 # some obscure symlink. paths copied from man systemd.unit.
1751 # possibly also usefull, but incomplete, doesnt show units not loaded in memory:
1752 # seru list-dependencies --reverse --all UNIT
1753 sysd-deps() {
1754 local f
1755 local -a dirs search
1756 ngset
1757
1758 case $1 in
1759 u)
1760 search=(
1761 ~/.config/systemd/user.control/*
1762 $XDG_RUNTIME_DIR/systemd/user.control/*
1763 $XDG_RUNTIME_DIR/systemd/transient/*
1764 $XDG_RUNTIME_DIR/systemd/generator.early/*
1765 ~/.config/systemd/user/*
1766 /etc/systemd/user/*
1767 $XDG_RUNTIME_DIR/systemd/user/*
1768 /run/systemd/user/*
1769 $XDG_RUNTIME_DIR/systemd/generator/*
1770 ~/.local/share/systemd/user/*
1771 /usr/lib/systemd/user/*
1772 $XDG_RUNTIME_DIR/systemd/generator.late/*
1773 )
1774 ;;
1775 *)
1776 search=(
1777 /etc/systemd/system.control/*
1778 /run/systemd/system.control/*
1779 /run/systemd/transient/*
1780 /run/systemd/generator.early/*
1781 /etc/systemd/system/*
1782 /etc/systemd/systemd.attached/*
1783 /run/systemd/system/*
1784 /run/systemd/systemd.attached/*
1785 /run/systemd/generator/*
1786 /lib/systemd/system/*
1787 /run/systemd/generator.late/*
1788 )
1789 ;;
1790 esac
1791 for f in "${search[@]}"; do
1792 [[ -d $f ]] || continue
1793 case $f in
1794 *.requires|*.wants)
1795 dirs+=("$f")
1796 ;;
1797 esac
1798 done
1799 # dirs is just so we write out the directory names, ls does it when there is 2 or more dirs.
1800 case ${#dirs[@]} in
1801 1)
1802 echo "${dirs[0]}:"
1803 ll "${dirs[@]}"
1804 ;;
1805 0) : ;;
1806 *)
1807 ll "${dirs[@]}"
1808 ;;
1809 esac
1810 ngreset
1811 }
1812
1813 fixvpndns() {
1814 local link istls
1815 read _ link _ istls < <(resolvectl dnsovertls tunfsf)
1816 case $istls in
1817 yes|no) : ;;
1818 *) echo fixvpndns error: unexpected istls value: $istls >&2; return 1 ;;
1819 esac
1820 s busctl call org.freedesktop.resolve1 /org/freedesktop/resolve1 org.freedesktop.resolve1.Manager SetLinkDNSOverTLS is $link no
1821 }
1822
1823 vpnoff() {
1824 [[ $1 ]] || { echo need arg; return 1; }
1825 if [[ -e /lib/systemd/system/openvpn-client@.service ]]; then
1826 local vpn_service=openvpn-client
1827 else
1828 local vpn_service=openvpn
1829 fi
1830 sudo systemctl stop $vpn_service@$1
1831 }
1832 vpnoffc() { # vpn off client
1833 ser stop openvpn-client-tr@client
1834 }
1835 vpnc() {
1836 ser start openvpn-client-tr@client
1837 }
1838
1839
1840 vspicy() { # usage: VIRSH_DOMAIN
1841 # connect to vms made with virt-install
1842 spicy -p $(sudo virsh dumpxml "$1"|grep "<graphics.*type='spice'"|\
1843 sed -r "s/.*port='([0-9]+).*/\1/")
1844 }
1845
1846 wian() {
1847 cat-new-files /m/4e/INBOX/new
1848 }
1849
1850 wtr() { curl wttr.in/boston; }
1851
1852 xevkb() { xev -event keyboard; }
1853
1854 # * misc stuff
1855
1856 vrun() {
1857 printf "running: %s\n" "$*"
1858 "$@"
1859 }
1860
1861 f=/a/f/ansible-configs/files/common/etc/fsf-workstation-bashrc.sh
1862 if [[ -e $f ]]; then
1863 # shellcheck disable=SC1090
1864 source $f
1865 fi
1866
1867
1868
1869
1870 reset-konsole() {
1871 # we also have a file in /a/c/...konsole...
1872 local f=$HOME/.config/konsolerc
1873 setini DefaultProfile profileian.profile "Desktop Entry" $f
1874 setini Favorites profileian.profile "Favorite Profiles" $f
1875 setini ShowMenuBarByDefault false KonsoleWindow $f
1876 setini TabBarPosition Top TabBar $f
1877 }
1878
1879 reset-sakura() {
1880 while read -r k v; do
1881 # shellcheck disable=SC2154
1882 setini $k $v sakura /a/c/subdir_files/.config/sakura/sakura.conf
1883 done <<'EOF'
1884 colorset1_back rgb(33,37,39)
1885 less_questions true
1886 audible_bell No
1887 visible_bell No
1888 disable_numbered_tabswitch true
1889 scroll_lines 10000000
1890 scrollbar true
1891 EOF
1892 }
1893
1894 reset-xscreensaver() {
1895 # except for spash, i set these by setting gui options in
1896 # xscreensaver-command -demo
1897 # then finding the corresponding option in .xscreensaver
1898 # spash, i happened to notice in .xscreensaver
1899 #
1900 # dpmsOff, monitor doesnt come back on using old free software supported nvidia card
1901 cat > /home/iank/.xscreensaver <<'EOF'
1902 mode: blank
1903 dpmsEnabled: True
1904 dpmsStandby: 0:07:00
1905 dpmsSuspend: 0:08:00
1906 dpmsOff: 0:00:00
1907 timeout: 0:05:00
1908 lock: True
1909 lockTimeout: 0:06:00
1910 splash: False
1911 EOF
1912
1913 }
1914
1915
1916 # * stuff that makes sense to be at the end
1917 if [[ "$SUDOD" ]]; then
1918 # allow failure, for example if we are sudoing into a user with diffferent/lesser permissions.
1919 cd "$SUDOD" ||:
1920 unset SUDOD
1921 elif [[ -d /a ]] && [[ $PWD == "$HOME" ]] && [[ $- == *i* ]]; then
1922 cd /a
1923 fi
1924
1925
1926
1927
1928 # for mitmproxy to get a newer python.
1929 # commented until i want to use it because it
1930 # noticably slows bash startup
1931 #
1932
1933 mypyenvinit () {
1934 if [[ $EUID == 0 || ! -e ~/.pyenv/bin ]]; then
1935 echo "error: dont be root. make sure pyenv is installed"
1936 return 1
1937 fi
1938 export PATH="$HOME/.pyenv/bin:$PATH"
1939 eval "$(pyenv init -)"
1940 eval "$(pyenv virtualenv-init -)"
1941 }
1942
1943
1944 export GOPATH=$HOME/go
1945 path-add $GOPATH/bin
1946 path-add /usr/local/go/bin
1947
1948 # I have the git repo and a release. either one should work.
1949 # I have both because I was trying to solve an issue that
1950 # turned out to be unrelated.
1951 # ARDUINO_PATH=/a/opt/Arduino/build/linux/work
1952 export ARDUINO_PATH=/a/opt/arduino-1.8.15
1953 export KALEIDOSCOPE_DIR=/a/opt/Kaleidoscope
1954
1955 # They want to be added to the start, but i think
1956 # that should be avoided unless we really need it.
1957 path-add --end ~/.npm-global
1958
1959
1960 path-add --end $HOME/.cargo/bin
1961
1962 if type -P rg &>/dev/null; then
1963 # --no-messages because of annoying errors on broken symlinks
1964 rg() { command rg --no-messages -L -i -M 300 --no-ignore "$@" || return $?; }
1965 #fails if not exist. ignore
1966 complete -r rg 2>/dev/null ||:
1967 else
1968 alias rg=grr
1969 fi
1970
1971
1972
1973 # taken from default changes to bashrc and bash_profile
1974 path-add --end --ifexists $HOME/.rvm/bin
1975 # also had ruby bin dir, but moved that to environment.sh
1976 # so its included in overall env
1977
1978
1979 export BASEFILE_DIR=/a/bin/fai-basefiles
1980
1981 #export ANDROID_HOME=/a/opt/android-home
1982 # https://f-droid.org/en/docs/Installing_the_Server_and_Repo_Tools/
1983 #export USE_SDK_WRAPPER=yes
1984 #PATH=$PATH:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools
1985
1986 # didnt get drush working, if I did, this seems like the
1987 # only good thing to include for it.
1988 # Include Drush completion.
1989 # if [ -f "/home/ian/.drush/drush.complete.sh" ] ; then
1990 # source /home/ian/.drush/drush.complete.sh
1991 # fi
1992
1993
1994 # best practice
1995 unset IFS
1996
1997 # https://wiki.archlinux.org/index.php/Xinitrc#Autostart_X_at_login
1998 # i added an extra condition as gentoo xorg guide says depending on
1999 # $DISPLAY is fragile.
2000 if [[ ! $DISPLAY && $XDG_VTNR == 1 ]] && shopt -q login_shell && isarch; then
2001 exec startx
2002 fi
2003
2004
2005 # ensure no bad programs appending to this file will have an affect
2006 return 0