various fixes
[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 dsign iankelling.org expertpathologyreview.com zroe.org amnimal.ninja
506 lipush
507 for h in li bk; do
508 m sl $h <<'EOF'
509 source ~/.bashrc
510 m dnsup
511 m dnsb8
512 EOF
513 done
514 }
515
516 dnsup() {
517 conflink
518 m ser reload bind9
519 }
520 dnsb8() {
521 local f=/var/lib/bind/db.b8.nz
522 ser stop bind9
523 sudo rm -fv $f.jnl
524 sudo install -m 644 -o bind -g bind /p/c/machine_specific/vps/bind-initial/db.b8.nz $f
525 ser restart bind9
526 }
527 dnsecgen() {
528 # keys generated like this
529 # because of https://ftp.isc.org/isc/dnssec-guide/dnssec-guide.pdf
530 # https://blog.apnic.net/2019/05/23/how-to-deploying-dnssec-with-bind-and-ubuntu-server/
531
532 # key length is longer than that guide because
533 # we are using those at fsf and when old key lengths
534 # become insecure, I want some extra time to update.
535 # dnsecgen (in brc2)
536
537 local zone=$1
538 dnssec-keygen -a RSASHA256 -b 2048 $zone
539 dnssec-keygen -f KSK -a RSASHA256 -b 4096 $zone
540 for f in K$zone.*.key; do
541 # eg Kb8.nz.+008+47995.key tag=47995
542 # in dnsimple, you add the long string from this.
543 # in gandi, you add the long string from the .key file,
544 # then see that the digest matches the ds.
545 echo "tag is the number after DS"
546 dnssec-dsfromkey -a SHA-256 $f
547 done
548 # For b8.nz, we let bind read the keys and sign, and
549 # right now they have root ownership, so let them
550 # get group read.
551 chmod g+r *.private
552 }
553 dsign() {
554 # create .signed file
555 # note: full paths probably not needed.
556 local arg
557 for arg; do
558 local zone=${arg#db.}
559 local dir=/p/c/machine_specific/vps/filesystem/var/lib/bind
560 dnssec-signzone -S -e +31536000 -o $zone -K $dir -d $dir $dir/db.$zone
561 done
562 }
563
564
565 #### begin bitcoin related things
566 btc() {
567 local f=/etc/bitcoin/bitcoin.conf
568 # importprivkey will timeout if using the default of 15 mins.
569 # upped it to 1 hour.
570 bitcoin-cli -rpcclienttimeout=60000 -$(s grep rpcuser= $f) -$(s grep rpcpassword= $f) "$@"
571 }
572 btcusd() { # $1 btc in usd
573 local price
574 price="$(curl -s https://api.coinbase.com/v2/prices/BTC-USD/spot | jq -r .data.amount)"
575 printf "$%s\n" "$price"
576 if [[ $1 ]]; then
577 printf "$%.2f\n" "$(echo "scale=4; $price * $1"| bc -l)"
578 fi
579 }
580 usdbtc() { # $1 usd in btc
581 local price
582 price="$(curl -s https://api.coinbase.com/v2/prices/BTC-USD/spot | jq -r .data.amount)"
583 printf "$%s\n" "$price"
584 if [[ $1 ]]; then
585 # 100 mil satoshi / btc. 8 digits after the 1.
586 printf "%.8f btc\n" "$(echo "scale=10; $1 / $price "| bc -l)"
587 fi
588 }
589 satoshi() { # $1 satoshi in usd
590 local price
591 price="$(curl -s https://api.coinbase.com/v2/prices/BTC-USD/spot | jq -r .data.amount)"
592 price=$(echo "scale=10; $price * 0.00000001"| bc -l)
593 printf "$%f\n" "$price"
594 if [[ $1 ]]; then
595 printf "$%.2f\n" "$(echo "scale=10; $price * $1"| bc -l)"
596 fi
597 }
598 #### end bitcoin related things
599
600
601
602 cbfstool () { /a/opt/coreboot/build/cbfstool "$@"; }
603
604
605 cgpl()
606 {
607 if (($#)); then
608 cp /a/bin/data/COPYING "$@"
609 else
610 cp /a/bin/data/COPYING .
611 fi
612 }
613
614 capache()
615 {
616 if (($#)); then
617 cp /a/bin/data/LICENSE "$@"
618 else
619 cp /a/bin/data/LICENSE .
620 fi
621 }
622
623 chrome() {
624 if type -p chromium &>/dev/null; then
625 cmd=chromium
626 else
627 cd /
628 cmd="schroot -c bullseye chromium"
629 CHROMIUM_FLAGS='--enable-remote-extensions' $cmd &r
630 fi
631 }
632
633
634 # do all tee.
635 # pipe to this, or just type like a shell
636 # todo: test this
637 dat() {
638 tee >(ssh frodo.b8.nz) >(ssh x2) >(ssh tp.b8.nz) >(ssh kw) >(ssh tp.b8.nz)
639 }
640 da() { # do all
641 local host
642 for host in x2 kw tp.b8.nz x3.b8.nz frodo.b8.nz; do
643 ssh $host "$@"
644 done
645 }
646
647
648 debian_pick_mirror () {
649 # netselect-apt finds a fast mirror.
650 # but we need to replace the mirrors ourselves,
651 # because it doesnt do that. best it can do is
652 # output a basic sources file
653 # here we get the server it found, get the main server we use
654 # then substitute all instances of one for the other in the sources file
655 # and backup original to /etc/apt/sources.list-original.
656 # this is idempotent. the only way to identify debian sources is to
657 # note the original server, so we put it in a comment so we can
658 # identify it later.
659 local file
660 file=$(mktemp -d)/f # safe way to get file name without creating one
661 sudo netselect-apt -o "$file" || return 1
662 url=$(grep ^\\w $file | head -n1 | awk '{print $2}')
663 sudo cp -f /etc/apt/sources.list /etc/apt/sources.list-original
664 sudo sed -ri "/http.us.debian.org/ s@( *[^ #]+ +)[^ ]+([^#]+).*@\1$url\2# http.us.debian.org@" /etc/apt/sources.list
665 sudo apt-get update
666 }
667 digme() {
668 digdiff @ns{1,2}.iankelling.org "$@"
669 }
670
671 tsr() { # ts run
672 "$@" |& ts || return $?
673 }
674
675 dup() {
676 local ran_d
677 ran_d=false
678 system-status _
679 case $PS1 in
680 *[\ \]]D\ *)
681 pushd /
682 /b/ds/distro-begin |& ts || return $?
683 /b/ds/distro-end |& ts || return $?
684 popd
685 ran_d=true
686 ;;&
687 *[\ \]]DB\ *)
688 pushd /
689 /b/ds/distro-begin |& ts || return $?
690 popd
691 ran_d=true
692 ;;
693 *[\ \]]DE\ *)
694 pushd /
695 /b/ds/distro-end |& ts || return $?
696 popd
697 ran_d=true
698 ;;&
699 *CONFLINK*)
700 if ! $ran_d; then
701 conflink
702 fi
703 ;;
704 esac
705 system-status _
706 }
707
708 envload() { # load environment from a previous: export > file
709 local file=${1:-$HOME/.${USER}_env}
710 eval "$(export | sed 's/^declare -x/export -n/')"
711 while IFS= read -r line; do
712 # declare -x makes variables local to a function
713 eval ${line/#declare -x/export}
714 done < "$file"
715 }
716
717 failfunc() { asdf a b c; }
718 failfunc2() { failfunc d e f; }
719
720 # one that comes with distros is too old for newer devices
721 fastboot() {
722 /a/opt/android-platform-tools/fastboot "$@";
723 }
724
725 kdecd() { /usr/lib/x86_64-linux-gnu/libexec/kdeconnectd; }
726
727 # List of apps to install/update
728 # Create from existing manually installed apps by doing
729 # fdroidcl update
730 # fdroidcl search -i, then manually removing
731 # automatically installed/preinstalled apps
732
733 #
734 # # my attempt at recovering from boot loop:
735 # # in that case, boot to recovery (volume up, home button, power, let go of power after samsun logo)
736 # # then
737 # mount /dev/block/mmcblk0p12 /data
738 # cd /data
739 # find -iname '*appname*'
740 # rm -rf FOUND_DIRS
741 # usually good enough to just rm -rf /data/app/APPNAME
742 #
743 # currently broken:
744 # # causes replicant to crash
745 # org.quantumbadger.redreader
746 # org.kde.kdeconnect_tp
747
748 # not broke, but wont work without gps
749 #com.zoffcc.applications.zanavi
750 # not broke, but not using atm
751 #com.nutomic.syncthingandroid
752 # # doesn\'t work on replicant
753 #net.sourceforge.opencamera
754 #
755 fdroid_pkgs=(
756 net.mullvad.mullvadvpn
757 org.schabi.newpipe
758 io.github.subhamtyagi.lastlauncher
759 io.anuke.mindustry
760 com.biglybt.android.client
761 de.marmaro.krt.ffupdater
762 me.ccrama.redditslide
763 org.fedorahosted.freeotp
764 at.bitfire.davdroid
765 com.alaskalinuxuser.justnotes
766 com.artifex.mupdf.viewer.app
767 com.danielkim.soundrecorder
768 com.fsck.k9
769 com.ichi2.anki
770 com.jmstudios.redmoon
771 com.jmstudios.chibe
772 org.kde.kdeconnect_tp
773 com.notecryptpro
774 com.termux
775 cz.martykan.forecastie
776 de.danoeh.antennapod
777 de.blinkt.openvpn
778 de.marmaro.krt.ffupdater
779 eu.siacs.conversations
780 free.rm.skytube.oss
781 im.vector.alpha # riot
782 info.papdt.blackblub
783 me.tripsit.tripmobile
784 net.gaast.giggity
785 net.minetest.minetest
786 net.osmand.plus
787 org.isoron.uhabits
788 org.linphone
789 org.gnu.icecat
790 org.smssecure.smssecure
791 org.yaaic
792 sh.ftp.rocketninelabs.meditationassistant.opensource
793 )
794 # https://forum.xda-developers.com/android/software-hacking/wip-selinux-capable-superuser-t3216394
795 # for maru,
796 #me.phh.superuser
797
798 fdup() {
799 local -A installed updated
800 local p
801 # tried putting this in go buildscript cronjob,
802 # but it failed with undefined: os.UserCacheDir. I expect its due to
803 # an environment variable missing, but its easier just to stick it here.
804 m go get -u mvdan.cc/fdroidcl || return 1
805 m fdroidcl update
806 if fdroidcl search -u | grep ^org.fdroid.fdroid; then
807 fdroidcl install org.fdroid.fdroid
808 sleep 5
809 m fdroidcl update
810 fi
811 for p in $(fdroidcl search -i| grep -o "^\S\+"); do
812 installed[$p]=true
813 done
814 for p in $(fdroidcl search -u| grep -o "^\S\+"); do
815 updated[$p]=false
816 done
817 for p in ${fdroid_pkgs[@]}; do
818 if ! ${installed[$p]:-false}; then
819 m fdroidcl install $p
820 # sleeps are just me being paranoid since replicant has a history of crashing when certain apps are installed
821 sleep 5
822 fi
823 done
824 for p in ${!installed[@]}; do
825 if ! ${updated[$p]:-true}; then
826 m fdroidcl install $p
827 sleep 5
828 fi
829 done
830 }
831
832 firefox-default-profile() {
833 key=Default value=1 section=$1
834 file=/p/c/subdir_files/.mozilla/firefox/profiles.ini
835 sed -ri "/^ *$key/d" "$file"
836 sed -ri "/ *\[$section\]/,/^ *\[[^]]+\]/{/^\s*$key[[:space:]=]/d};/ *\[$section\]/a $key=$value" "$file"
837 }
838 fdhome() { #firefox default home profile
839 firefox-default-profile Profile0
840 }
841
842 fdwork() {
843 firefox-default-profile Profile4
844 }
845
846 ff() {
847 if type -P firefox &>/dev/null; then
848 firefox "$@"
849 else
850 iceweasel "$@"
851 fi
852 }
853
854 fn() {
855 firefox -P alt "$@" >/dev/null 2>&1
856 }
857
858
859 fsdiff () {
860 local missing=false
861 local dname="${PWD##*/}"
862 local m="/a/tmp/$dname-missing"
863 local d="/a/tmp/$dname-diff"
864 [[ -e $d ]] && rm "$d"
865 [[ -e $m ]] && rm "$m"
866 local msize=0
867 local fsfile
868 while read -r line; do
869 fsfile="$1${line#.}"
870 if [[ -e "$fsfile" ]]; then
871 md5diff "$line" "$fsfile" && tee -a "/a/tmp/$dname-diff" <<< "$fsfile $line"
872 else
873 missing=true
874 echo "$line" >> "$m"
875 msize=$((msize + 1))
876 fi
877 done < <(find . -type f )
878 if $missing; then
879 echo "$m"
880 (( msize <= 100 )) && cat $m
881 fi
882 }
883 fsdiff-test() {
884 # expected output, with different tmp dirs
885 # /tmp/tmp.HDPbwMqdC9/c/d ./c/d
886 # /a/tmp/tmp.qLDkYxBYPM-missing
887 # ./b
888 cd $(mktemp -d)
889 echo ok > a
890 echo nok > b
891 mkdir c
892 echo ok > c/d
893 local x
894 x=$(mktemp -d)
895 mkdir $x/c
896 echo different > $x/c/d
897 echo ok > $x/a
898 fsdiff $x
899 }
900 rename-test() {
901 # test whether missing files were renamed, generally for use with fsdiff
902 # $1 = fsdiff output file, $2 = directory to compare to. pwd = fsdiff dir
903 # echos non-renamed files
904 local x y found
905 unset sums
906 for x in "$2"/*; do
907 { sums+=( "$(md5sum < "$x")" ) ; } 2>/dev/null
908 done
909 while read -r line; do
910 { missing_sum=$(md5sum < "$line") ; } 2>/dev/null
911 renamed=false
912 for x in "${sums[@]}"; do
913 if [[ $missing_sum == "$x" ]]; then
914 renamed=true
915 break
916 fi
917 done
918 $renamed || echo "$line"
919 done < "$1"
920 return 0
921 }
922
923 feh() {
924 # F = fullscren, z = random, Z = auto zoom
925 command feh -FzZ "$@"
926 }
927
928
929
930 fw() {
931 firefox -P default "$@" >/dev/null 2>&1
932 }
933
934 gitian() {
935 git config user.email ian@iankelling.org
936 }
937
938 # at least in flidas, things rely on gpg being gpg1
939 gpg() {
940 if type -P gpg2 &>/dev/null; then
941 command gpg2 "$@"
942 else
943 command gpg "$@"
944 fi
945 }
946
947 gse() {
948 local email=ian@iankelling.org
949 git send-email --notes "--envelope-sender=<$email>" \
950 --suppress-cc=self "$@"
951 }
952
953 gup() { /a/f/gnulib/build-aux/gnupload "$@"; }
954
955 dejagnu() { /a/opt/dejagnu/dejagnu "$@"; }
956
957 hstatus() {
958 # do git status on published repos.
959 c /a/bin/githtml
960 for x in *; do
961 cd $(readlink -f $x)/..
962 status=$(i status -s) || pwd
963 if [[ $status ]]; then
964 hr
965 echo $x
966 printf "%s\n" "$status"
967 fi
968 cd /a/bin/githtml
969 done
970 }
971
972 # work log
973 wlog() {
974 local day now i
975 now=$(date +%s)
976 for (( i=0; i<60; i++ )); do
977 day=$( date +%F -d @$((now - 86400*i )) )
978 date "+%a %b %d" -d @$((now - 86400*i )) | tr '\n' ' '
979 /a/opt/timetrap/bin/t d -ftotal -s $day -e $day all -m '^w|lunch$'
980 done
981 }
982 to() { t out -a "$@"; }
983 ti() { t in -a "$@"; }
984 tl() {
985 to "$*"
986 t s lunch
987 t in -a "$*"
988 m t out -a $(date +%F.%T -d @$(( $(date -d "$(echo $*|sed 's/[_.]/ /g')" +%s) + 60*45 )) )
989 t s w
990 }
991
992 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}' ; }
993
994 idea() {
995 /a/opt/idea-IC-163.7743.44/bin/idea.sh "$@" &r
996 }
997
998 ilogs() {
999 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"
1000 }
1001
1002 ilog() {
1003 chan=${1:-#fsfsys}
1004 # use * instead of -r since that does sorted order
1005 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
1006 }
1007
1008 o() {
1009 if type gio &> /dev/null ; then
1010 gio open "$@"
1011 elif type gvfs-open &> /dev/null ; then
1012 gvfs-open "$@"
1013 else
1014 xdg-open "$@"
1015 fi
1016 # another alternative is run-mailcap
1017 }
1018 ccomp xdg-open o
1019
1020 # jfilter() {
1021 # grep -Evi -e "^(\S+\s+){4}(sudo|sshd|cron)\[\S*:" \
1022 # -e "^(\S+\s+){4}systemd\[\S*: (starting|started) (btrfsmaintstop|dynamicipupdate|spamd dns bug fix cronjob|rss2email)\.*$"
1023 # }
1024 # jtail() {
1025 # journalctl -n 10000 -f "$@" | jfilter
1026 # }
1027 # jr() { journalctl "$@" | jfilter | less ; }
1028 # jrf() { journalctl -n 200 -f "$@" | jfilter; }
1029
1030 jr() { journalctl "$@" ; }
1031 jrf() { journalctl -n 200 -f "$@" ; }
1032
1033
1034 ccomp journalctl jtail jr jrf
1035
1036 kff() { # keyboardio firmware flash
1037 pushd /a/bin/distro-setup/Arduino/Model01-Firmware
1038 yes $'\n' | make flash
1039 popd
1040 }
1041
1042 wgkey() {
1043 local umask_orig name
1044 if (( $# != 1 )); then
1045 e expected 1 arg >&2
1046 return 1
1047 fi
1048 name=$1
1049 umask_orig=$(umask)
1050 umask 0077
1051 wg genkey | tee $name-priv.key | wg pubkey > $name-pub.key
1052 umask $umask_orig
1053 }
1054 wghole() {
1055 if (( $# != 2 )); then
1056 e expected 2 arg of hostname, ip suffix >&2
1057 return 1
1058 fi
1059 local host ipsuf umask_orig
1060 host=$1
1061 ipsuf=$2
1062 mkdir -p /p/c/machine_specific/$host/filesystem/etc/wireguard
1063 cd /p/c/machine_specific/$host/filesystem/etc/wireguard
1064 umask_orig=$(umask)
1065 umask 0077
1066 wg genkey | tee hole-priv.key | wg pubkey > hole-pub.key
1067 cat >wghole.conf <<EOF
1068 [Interface]
1069 # contents hole-priv.key
1070 PrivateKey = $(cat hole-priv.key)
1071 ListenPort = 1194
1072 Address = 10.8.0.$ipsuf/24
1073 # https://dev.to/tangramvision/what-they-don-t-tell-you-about-setting-up-a-wireguard-vpn-1h2g
1074 # ||: makes the systemd service not fail due to the failed command
1075 PostUp = ping -c1 10.8.0.1 ||:
1076
1077 [Peer]
1078 # li
1079 PublicKey = zePGl7LoS3iv6ziTI/k8BMh4L3iL3K2t9xJheMR4hQA=
1080 AllowedIPs = 10.8.0.0/24
1081 Endpoint = 72.14.176.105:1194
1082 PersistentKeepalive = 25
1083 EOF
1084 umask $umask_orig
1085 # old approach. systemd seems to work fine and cleaner.
1086 rm -f ../network/interfaces.d/wghole
1087 cedit -q $host /p/c/machine_specific/li/filesystem/etc/wireguard/wghole.conf <<EOF || [[ $? == 1 ]]
1088 [Peer]
1089 PublicKey = $(cat hole-pub.key)
1090 AllowedIPs = 10.8.0.$ipsuf/32
1091 EOF
1092 cd - >/dev/null
1093 }
1094
1095
1096 lom() {
1097 local l base
1098 if [[ $1 == /* ]]; then
1099 base=${1##*/}
1100 if mountpoint -q /mnt/$base; then
1101 return 0
1102 fi
1103 l=$(losetup -j $1 | sed -rn 's/^([^ ]+): .*/\1/p' | head -n1 ||:)
1104 if [[ ! $l ]]; then
1105 l=$(sudo losetup -f)
1106 m sudo losetup $l $1
1107 fi
1108 if ! sudo cryptsetup status /dev/mapper/$base &>/dev/null; then
1109 if ! sudo cryptsetup luksOpen $l $base; then
1110 m sudo losetup -d $l
1111 return 1
1112 fi
1113 fi
1114 m sudo mkdir -p /mnt/$base
1115 m sudo mount /dev/mapper/$base /mnt/$base
1116 m sudo chown $USER:$USER /mnt/$base
1117 else
1118 base=$1
1119 if mountpoint /mnt/$base &>/dev/null; then
1120 m sudo umount /mnt/$base
1121 fi
1122 if sudo cryptsetup status /dev/mapper/$base &>/dev/null; then
1123 if ! m sudo cryptsetup luksClose /dev/mapper/$base; then
1124 echo lom: failed cryptsetup luksClose /dev/mapper/$base
1125 return 1
1126 fi
1127 fi
1128 l=$(losetup -l --noheadings | awk '$6 ~ /\/'$1'$/ {print $1}')
1129 if [[ $l ]]; then
1130 m sudo losetup -d $l
1131 else
1132 echo lom: warning: no loopback device found
1133 fi
1134 fi
1135 }
1136
1137 # mu personality. for original, just run mp. for 2, run mp 2.
1138 # this is partly duplicated in mail-setup
1139 mp() {
1140 local dead=false
1141 for s in {1..5}; do
1142 if ! killall mu; then
1143 dead=true
1144 break
1145 fi
1146 sleep 1
1147 done
1148 if ! $dead; then
1149 echo error: mu not dead
1150 m psg mu
1151 return 1
1152 fi
1153 suf=$1
1154 set -- /m/mucache ~/.cache/mu /m/.mu ~/.config/mu
1155 while (($#)); do
1156 target=$1$suf
1157 f=$2
1158 shift 2
1159 if [[ -e $f && ! -L $f ]]; then
1160 m rm -rf $f
1161 fi
1162 m ln -sf -T $target $f
1163 done
1164 }
1165
1166 # these might need a mu index or something added.
1167 mbenable() {
1168 local mb=$1
1169 dst=/m/4e/$mb
1170 src=/m/md/$mb
1171 [[ -e $src ]] || { echo "src:$src does not exist"; return 1; }
1172 m mv -T $src $dst
1173 m ln -s -T $dst $src
1174 }
1175 mb2enable() {
1176 local mb
1177 for mb; do
1178 dst=/m/4e2/$mb
1179 link=/m/md/$mb
1180 src=/m/md/$mb
1181 if [[ ! -e $src || -L $src ]]; then
1182 src=/m/4e/$mb
1183 fi
1184 [[ -e $src ]] || { echo "src:$src does not exist"; return 1; }
1185 m mv -T $src $dst
1186 m ln -sf -T $dst $link
1187 done
1188 }
1189 mbdisable() {
1190 local mb=$1
1191 dst=/m/md/$mb
1192 src=/m/4e/$mb
1193 set -x
1194 [[ -e $src ]] || { set +x; return 1; }
1195 if [[ -L $dst ]]; then rm $dst; fi
1196 mv -T $src $dst
1197 set +x
1198 }
1199
1200
1201 mdt() {
1202 markdown "$1" >/tmp/mdtest.html
1203 firefox /tmp/mdtest.html
1204 }
1205
1206 mo() { xset dpms force off; } # monitor off
1207
1208 mpvd() {
1209 mpv --profile=d "$@";
1210 }
1211 mpvs() {
1212 mpv --profile=s "$@";
1213 }
1214
1215 myirc() {
1216 if [[ ! $1 ]]; then
1217 set -- fsf-office
1218 fi
1219 local d1 d2
1220 d=( /var/lib/znc/moddata/log/iank/{freenode,libera} )
1221 # use * instead of -r since that does sorted order
1222 ssh root@iankelling.org "for f in ${d[@]}; do cd \$f/#$1; grep '\<iank.*' *; done" | cut --complement -c12-16
1223 }
1224 mypidgin() {
1225 c /p/c/.purple/logs/jabber/iank@fsf.org/office@conference.fsf.org.chat
1226 for x in *.html; do html2text -o ${x%.html}.txt $x; done;
1227 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}'
1228 }
1229 allmyirc() {
1230 local d
1231 d=/var/lib/znc/moddata/log/iank/freenode
1232 ssh root@iankelling.org "cd $d; find . -mtime -60 -type f -exec grep '\<iank.*' {} +" | sed -r 's,^..([^/]*)/(.{11})(.{5})(.{8}).,\2\4 \1,' | sort
1233 }
1234
1235 mygajim() {
1236 local now time time_sec time_pretty
1237 now=$(date +%s)
1238 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
1239 case $time in
1240 16*) : ;;
1241 *) continue ;;
1242 esac
1243 if ! time_pretty=$(date +%F.%R -d @$time); then
1244 echo bad time: $time
1245 return 1
1246 fi
1247 echo $time_pretty "$l"
1248 time_sec=${time%%.*}
1249 # only look at the last 18 days. generally just use this for timesheet.
1250 if (( time_sec < now - 60 * 60 * 24 * 18 )); then break; fi
1251 done
1252 }
1253
1254 gajlogs() {
1255 sqlite3 -separator ' ' /p/c/subdir_files/.local/share/gajim/logs.db "select time, message from logs" | less
1256 }
1257
1258 net-dev-info() {
1259 e "lspci -nnk|gr -iA2 net"
1260 lspci -nnk|gr -iA2 net
1261 hr
1262 e "s lshw -C network"
1263 hr
1264 sudo lshw -C network
1265 }
1266
1267 nk() {
1268 ser stop NetworkManager
1269 ser disable NetworkManager
1270 ser stop NetworkManager-wait-online.service
1271 ser disable NetworkManager-wait-online.service
1272 ser stop dnsmasq
1273 sudo resolvconf -d NetworkManager
1274 # ser start dnsmasq
1275 sudo ifup br0
1276 }
1277 ngo() {
1278 sudo ifdown br0
1279 ser start NetworkManager
1280 sleep 4
1281 sudo nmtui-connect
1282 }
1283
1284 otp() {
1285 oathtool --totp -b "$*" | xclip -selection clipboard
1286 }
1287 j() {
1288 "$@" |& pee "xclip -r -selection clipboard"
1289 }
1290
1291
1292 pakaraoke() {
1293 # from http://askubuntu.com/questions/456021/remove-vocals-from-mp3-and-get-only-instrumentals
1294 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
1295 }
1296
1297 pfind() { #find *$1* in $PATH
1298 [[ $# != 1 ]] && { echo requires 1 argument; return 1; }
1299 local pathArray
1300 IFS=: pathArray=($PATH); unset IFS
1301 find "${pathArray[@]}" -iname "*$1*"
1302 }
1303
1304 pick-trash() {
1305 # trash-restore lists everything that has been trashed at or below CWD
1306 # This picks out files just in CWD, not subdirectories,
1307 # which also match grep $1, usually use $1 for a time string
1308 # which you get from running restore-trash once first
1309 local name x ask
1310 local nth=1
1311 # last condition is to not ask again for ones we skipped
1312 while name="$( echo | restore-trash | gr "$PWD/[^/]\+$" | gr "$1" )" \
1313 && [[ $name ]] && (( $(wc -l <<<"$name") >= nth )); do
1314 name="$(echo "$name" | head -n $nth | tail -n 1 )"
1315 read -r -p "$name [Y/n] " ask
1316 if [[ ! $ask || $ask == [Yy] ]]; then
1317 x=$( echo "$name" | gr -o "^\s*[0-9]*" )
1318 echo $x | restore-trash > /dev/null
1319 elif [[ $ask == [Nn] ]]; then
1320 nth=$((nth+1))
1321 else
1322 return
1323 fi
1324 done
1325 }
1326
1327
1328 pub() {
1329 rld /a/h/_site/ li:/var/www/iankelling.org/html
1330 }
1331
1332
1333 pumpa() {
1334 # fixes the menu bar in xmonad. this won\'t be needed when xmonad
1335 # packages catches up on some changes in future (this is written in
1336 # 4/2017)
1337 #
1338 # geekosaur: so youll want to upgrade to xmonad 0.13 or else use a
1339 # locally modified XMonad.Hooks.ManageDocks that doesnt set the
1340 # work area; turns out it\'s impossible to set correctly if you are
1341 # not a fully EWMH compliant desktop environment
1342 #
1343 # geekosaur: chrome shows one failure mode, qt/kde another, other
1344 # gtk apps a third, ... I came up with a setting that works for me
1345 # locally but apparently doesnt work for others, so we joined the
1346 # other tiling window managers in giving up on setting it at all
1347 #
1348 xprop -root -remove _NET_WORKAREA
1349 command pumpa & r
1350 }
1351
1352 # reviewboard, used at my old job
1353 #rbpipe() { rbt post -o --diff-filename=- "$@"; }
1354 #rbp() { rbt post -o "$@"; }
1355
1356 rebr() {
1357 sudo ifdown br0
1358 sudo ifup br0
1359 }
1360
1361
1362 # only run on MAIL_HOST. simpler to keep this on one system.
1363 r2eadd() { # usage: name url
1364 # initial setup of rss2email:
1365 # r2e new r2e@iankelling.org
1366 # that initializes files, and sets default email.
1367 # symlink to the config doesnt work, so I copied it to /p/c
1368 # and then use cli option to specify explicit path.
1369 # Only option changed from default config is to set
1370 # force-from = True
1371 #
1372 # or else for a few feeds, the from address is set by the feed, and
1373 # if I fail delivery, then I send a bounce message to that from
1374 # address, which makes me be a spammer.
1375
1376 r2e add $1 "$2" $1@r2e.iankelling.org
1377 # get up to date and dont send old entries now:
1378 r2e run --no-send $1
1379 }
1380 r2e() { command r2e -d /p/c/rss2email.json -c /p/c/rss2email.cfg "$@"; }
1381
1382 rspicy() { # usage: HOST DOMAIN
1383 # connect to spice vm remote host. use vspicy for local host
1384 local port
1385 # shellcheck disable=SC2087
1386 port=$(ssh $1<<EOF
1387 sudo virsh dumpxml $2|grep "<graphics.*type='spice'" | \
1388 sed -rn "s/.*port='([0-9]+).*/\1/p"
1389 EOF
1390 )
1391 if [[ $port ]]; then
1392 spicy -h $1 -p $port
1393 else
1394 echo "error: no port found. check that the domain is running."
1395 fi
1396 }
1397
1398
1399 scssl() {
1400 # s gem install scss-lint
1401 pushd /a/opt/thoughtbot-guides
1402 git pull --stat
1403 popd
1404 scss-lint -c /a/opt/thoughtbot-guides/style/sass/.scss-lint.yml "$@"
1405 }
1406
1407 skbrc() {
1408 sk -e 2120,245 /b/ds/brc /b/ds/brc2
1409 }
1410
1411 skaraoke() {
1412 local tmp out
1413 out=${2:-${1%.*}.sh}
1414 tmp=$(mktemp -d)
1415 script -t -c "mpv --no-config --no-resume-playback --no-terminal --no-audio-display '$1'" $tmp/typescript 2>$tmp/timing
1416 # todo, the current sleep seems pretty good, but it
1417 # would be nice to have an empirical measurement, or
1418 # some better wait to sync up.
1419 #
1420 # note: --loop-file=no prevents it from hanging if you have that
1421 # set to inf the mpv config.
1422 # --loop=no prevents it from exit code 3 due to stdin if you
1423 # had it set to inf in mpv config.
1424 #
1425 # args go to mpv, for example --volume=80, 50%
1426 cat >$out <<EOFOUTER
1427 #!/bin/bash
1428 trap "trap - TERM && kill 0" INT TERM ERR; set -e
1429 ( sleep .2; scriptreplay <( cat <<'EOF'
1430 $(cat $tmp/timing)
1431 EOF
1432 ) <( cat <<'EOF'
1433 $(cat $tmp/typescript)
1434 EOF
1435 ))&
1436 base64 -d - <<'EOF'| mpv --loop=no --loop-file=no --no-terminal --no-audio-display "\$@" -
1437 $(base64 "$1")
1438 EOF
1439 kill 0
1440 EOFOUTER
1441 rm -r $tmp
1442 chmod +x $out
1443 }
1444
1445 smeld() { # ssh meld usage host1 host2 file
1446 meld <(ssh $1 cat $3) <(ssh $2 cat $3)
1447 }
1448
1449 spd() {
1450 PATH=/usr/local/spdhackfix:$PATH command spd "$@"
1451 }
1452
1453 spend() {
1454 sudo systemctl suspend
1455 }
1456
1457 spamf() { # spamtest on FILE
1458 local spamcpre spamdpid
1459
1460 if (( $# != 1 )); then
1461 e spamtest error: expected 1 arg, filename >&2
1462 return 1
1463 fi
1464
1465 spamdpid=$(systemctl status spamassassin| sed -n '/^ *Main PID:/s/[^0-9]//gp')
1466 spamcpre="nsenter -t $spamdpid -n -m"
1467 s $spamcpre sudo -u Debian-exim spamassassin -t --cf='score PYZOR_CHECK 0' <"$1"
1468 }
1469
1470
1471 # mail related
1472 testmail() {
1473 declare -gi _seq; _seq+=1
1474 echo "test body" | m mail -s "test mail from $HOSTNAME, $_seq" "${@:-root@localhost}"
1475 # for testing to send from an external address, you can do for example
1476 # -fian@iank.bid -aFrom:ian@iank.bid web-6fnbs@mail-tester.com
1477 # note in exim, you can retry a deferred message
1478 # s exim -M MSG_ID
1479 # MSG_ID is in /var/log/exim4/mainlog, looks like 1ccdnD-0001nh-EN
1480 }
1481
1482 # to test sieve, use below command. for fsf mail, see offlineimap-sync script
1483 # make modifications, then copy to live file, use -eW to actually modify mailbox
1484 #
1485 # Another option is to use sieve-test SCRIPT MAIL_FILE. note,
1486 # sieve-test doesnt know about envelopes, Im not sure if sieve-filter does.
1487
1488 # sieve with output filter. arg is mailbox, like INBOX.
1489 # This depends on dovecot conf, notably mail_location in /etc/dovecot/conf.d/10-mail.conf
1490
1491 # always run this first, edit the test files, then run the following
1492 testsieve() {
1493 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
1494 }
1495 runsieve() {
1496 c ~/sieve; cp personal{test,}.sieve; cp lists{test,}.sieve; cp personalend{test,}.sieve
1497 sieve-filter -eWv ~/sieve/maintest.sieve ${1:-INBOX} delete &> /tmp/testsieve.log
1498 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
1499 }
1500
1501 # usage:
1502 # alertme SUBJECT
1503 # printf "subject\nbody\n" | alertme
1504 alertme() {
1505 if [[ -t 0 ]]; then
1506 exim -t <<EOF
1507 From: alertme@b8.nz
1508 To: alerts@iankelling.org
1509 Subject: $*
1510 EOF
1511 else
1512 read sub
1513 { cat <<EOF
1514 From: alertme@b8.nz
1515 To: alerts@iankelling.org
1516 Subject: $sub
1517
1518 EOF
1519 cat
1520 } | exim -t
1521 fi
1522 }
1523 daylertme() {
1524 if [[ -t 0 ]]; then
1525 exim -t <<EOF
1526 From: alertme@b8.nz
1527 To: daylerts@iankelling.org
1528 Subject: $*
1529 EOF
1530 else
1531 read sub
1532 { cat <<EOF
1533 From: alertme@b8.nz
1534 To: daylerts@iankelling.org
1535 Subject: $sub
1536
1537 EOF
1538 cat
1539 } | exim -t
1540 fi
1541 }
1542
1543 # alert when a page goes live. not urgent.
1544 alert200() {
1545 url="$1"
1546 tmpdir="$(mktemp -d)"
1547 cd $tmpdir
1548 while true; do
1549 if torsocks wget -q "$url"; then
1550 alertme $tmpdir
1551 fi
1552 sleep 600 + $(( RANDOM % 300 ))
1553 done
1554 }
1555
1556
1557 # mail related
1558 testexim() {
1559 # testmail above calls sendmail, which is a link to exim/postfix.
1560 # its docs dont say a way of adding an argument
1561 # to sendmail to turn on debug output. We could make a wrapper, but
1562 # that is a pain. Exim debug args are documented here:
1563 # http://www.exim.org/exim-html-current/doc/html/spec_html/ch-the_exim_command_line.html
1564 #
1565 # http://www.exim.org/exim-html-current/doc/html/spec_html/ch-building_and_installing_exim.html
1566 # note, for exim daemon, you can turn on debug options by
1567 # adding -d, etc to COMMONOPTIONS in
1568 # /etc/default/exim4
1569 #
1570 # to specify recipients other than those in to, cc, bcc, you can use the cli args, eg:
1571 # exim -t 'test@zroe.org, t2@zroe.org' <<'EOF'
1572 #
1573 # -t = get recipient from header
1574 exim -d -t <<'EOF'
1575 From: i@dmarctest.b8.nz
1576 To: mailman@dev.fsf.org
1577 Subject: test2
1578 Reply-to: rtest@iankelling.org
1579
1580 This is a test message.
1581 EOF
1582 }
1583
1584 # toggle keyboard
1585 tk() {
1586 # based on
1587 # https://askubuntu.com/questions/160945/is-there-a-way-to-disable-a-laptops-internal-keyboard
1588 id=$(xinput --list --id-only 'AT Translated Set 2 keyboard')
1589 if xinput list | grep -F '∼ AT Translated Set 2 keyboard' &>/dev/null; then
1590 echo enabling keyboard
1591 # find the first slave keyboard number, they are all the same in my output.
1592 # if they werent, worst case we would need to save the slave number somewhere
1593 # when it got disabled.
1594 slave=$(xinput list | sed -n 's/.*slave \+keyboard (\([0-9]*\)).*/\1/p' | head -n1)
1595 xinput reattach $id $slave
1596 else
1597 xinput float $id
1598 fi
1599 }
1600
1601 tm() {
1602 # timer in minutes
1603 # --no-config
1604 (sleep $(calc "$* * 60") && mpv --no-config --volume 50 /a/bin/data/alarm.mp3) > /dev/null 2>&1 &
1605 }
1606
1607 trg() { transmission-remote-gtk & r; }
1608 trc() {
1609 # example, set global upload limit to 100 kilobytes:
1610 # trc -u 100
1611 TR_AUTH=":$(jq -r .profiles[0].password ~/.config/transmission-remote-gtk/config.json)" transmission-remote transmission.lan -ne "$@"
1612 }
1613
1614 trysleep() {
1615 retries="$1"
1616 sleepsecs="$2"
1617 shift 2
1618 for (( i=0; i < retries - 1; i++ )); do
1619 if "$@"; then
1620 return 0
1621 fi
1622 sleep $sleepsecs
1623 done
1624 "$@"
1625 }
1626
1627
1628 tu() {
1629 local s
1630 if [[ -e $1 && ! -w $1 || ! -w $(dirname "$1") ]]; then
1631 s=s;
1632 fi
1633 # full path for using in some initial setup steps
1634 $s /a/exe/teeu "$@"
1635 }
1636
1637 enn() {
1638 local ecmd pid
1639
1640 ecmd="/usr/sbin/exim4 -C /etc/exim4/my.conf"
1641 if ip a show veth1-mail &>/dev/null; then
1642 s $ecmd "$@"
1643 return
1644 fi
1645 pid=$(pgrep -f "/usr/sbin/exim4 -bd -q30m -C /etc/exim4/my.conf"|h1)
1646 m s nsenter -t $pid -n -m $ecmd "$@"
1647 }
1648
1649 sdnbash() { # systemd namespace bash
1650 local unit=$1
1651 m sudo nsenter -t $(systemctl show --property MainPID --value $unit') -n -m sudo -u $USER -i bash
1652 }
1653
1654 mailnnbash() {
1655 m sudo nsenter -t $(systemctl show --property MainPID --value mailnn') -n -m sudo -u $USER -i bash
1656 }
1657
1658 mailvpnbash() {
1659 m sudo nsenter -t $(pgrep -f "/usr/sbin/openvpn .* --config /etc/openvpn/.*mail.conf") -n -m sudo -u $USER -i bash
1660 }
1661 eximbash() {
1662 m sudo nsenter -t $(pgrep -f "/usr/sbin/exim4 -bd -q30m -C /etc/exim4/my.conf"|h1) -n -m sudo -u $USER -i bash
1663 }
1664 spamnn() {
1665 local spamdpid
1666 spamdpid=$(systemctl show --property MainPID --value spamassassin)
1667 m sudo nsenter -t $spamdpid -n -m sudo -u Debian-exim spamassassin "$@"
1668 }
1669 unboundbash() {
1670 m sudo nsenter -t $(systemctl status unbound| sed -n '/^ *Main PID:/s/[^0-9]//gp') -n -m sudo -u $USER -i bash
1671 }
1672
1673 mailnncheck() {
1674 local p pid ns mailnn
1675 # mailvpn would belong on the list if using openvpn
1676 for p in mailnn unbound dovecot spamassassin exim4 radicale; do
1677 case $p in
1678 exim4|radicale)
1679 pid=$(ps -eo pid,cgroup | grep /system.slice/$p.service | awk '{print $1}')
1680 ;;
1681 *)
1682 pid=$(s systemctl show --property MainPID --value $p)
1683 ;;
1684 esac
1685 echo p=$p pid=$pid
1686 if [[ ! $pid ]]; then
1687 echo failed to find pid for $p
1688 continue
1689 fi
1690 if ! ns=$(s readlink /proc/$pid/ns/net); then
1691 echo failed to find ns for $p pid=$pid
1692 continue
1693 fi
1694 if [[ $mailnn ]]; then
1695 if [[ $ns != "$mailnn" ]]; then
1696 echo "$p ns $ns != $mailnn"
1697 fi
1698 else
1699 mailnn=$ns
1700 fi
1701 done
1702
1703 }
1704
1705
1706 vpncmd() {
1707 m sudo -E env "PATH=$PATH" nsenter -t $(pgrep -f "/usr/sbin/openvpn .* --config /etc/openvpn/.*client.conf") -n -m "$@"
1708 }
1709 vpnf() {
1710 vpncmd sudo -E -u iank env "PATH=$PATH" abrowser -no-remote -P vpn & r
1711 }
1712 vpn2f() {
1713 vpncmd sudo -u iank env "PATH=$PATH" abrowser -no-remote -P vpn2 & r
1714 }
1715
1716 vpni() {
1717 vpncmd sudo -u iank env "PATH=$PATH" "$@"
1718 }
1719 vpnbash() {
1720 vpncmd bash
1721 }
1722
1723
1724 vpn() {
1725 if [[ -e /lib/systemd/system/openvpn-client@.service ]]; then
1726 local vpn_service=openvpn-client
1727 else
1728 local vpn_service=openvpn
1729 fi
1730
1731 [[ $1 ]] || { echo need arg; return 1; }
1732 journalctl --unit=$vpn_service@$1 -f -n0 &
1733 # sometimes the journal doesnt open until after the vpn output
1734 # has happened. hoping this fixes that.
1735 sleep 1
1736 sudo systemctl start $vpn_service@$1
1737 # sometimes the ask-password agent does not work and needs a delay.
1738 sleep .5
1739 # https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=779240
1740 # noticed around 8-2017 after update from around stretch release
1741 # on debian testing, even though the bug is much older.
1742 sudo systemd-tty-ask-password-agent
1743 }
1744
1745 # systemctl is-enabled / status / cat says nothing, instead theres
1746 # some obscure symlink. paths copied from man systemd.unit.
1747 # possibly also usefull, but incomplete, doesnt show units not loaded in memory:
1748 # seru list-dependencies --reverse --all UNIT
1749 sysd-deps() {
1750 local f
1751 local -a dirs search
1752 ngset
1753
1754 case $1 in
1755 u)
1756 search=(
1757 ~/.config/systemd/user.control/*
1758 $XDG_RUNTIME_DIR/systemd/user.control/*
1759 $XDG_RUNTIME_DIR/systemd/transient/*
1760 $XDG_RUNTIME_DIR/systemd/generator.early/*
1761 ~/.config/systemd/user/*
1762 /etc/systemd/user/*
1763 $XDG_RUNTIME_DIR/systemd/user/*
1764 /run/systemd/user/*
1765 $XDG_RUNTIME_DIR/systemd/generator/*
1766 ~/.local/share/systemd/user/*
1767 /usr/lib/systemd/user/*
1768 $XDG_RUNTIME_DIR/systemd/generator.late/*
1769 )
1770 ;;
1771 *)
1772 search=(
1773 /etc/systemd/system.control/*
1774 /run/systemd/system.control/*
1775 /run/systemd/transient/*
1776 /run/systemd/generator.early/*
1777 /etc/systemd/system/*
1778 /etc/systemd/systemd.attached/*
1779 /run/systemd/system/*
1780 /run/systemd/systemd.attached/*
1781 /run/systemd/generator/*
1782 /lib/systemd/system/*
1783 /run/systemd/generator.late/*
1784 )
1785 ;;
1786 esac
1787 for f in "${search[@]}"; do
1788 [[ -d $f ]] || continue
1789 case $f in
1790 *.requires|*.wants)
1791 dirs+=("$f")
1792 ;;
1793 esac
1794 done
1795 # dirs is just so we write out the directory names, ls does it when there is 2 or more dirs.
1796 case ${#dirs[@]} in
1797 1)
1798 echo "${dirs[0]}:"
1799 ll "${dirs[@]}"
1800 ;;
1801 0) : ;;
1802 *)
1803 ll "${dirs[@]}"
1804 ;;
1805 esac
1806 ngreset
1807 }
1808
1809 fixvpndns() {
1810 local link istls
1811 read _ link _ istls < <(resolvectl dnsovertls tunfsf)
1812 case $istls in
1813 yes|no) : ;;
1814 *) echo fixvpndns error: unexpected istls value: $istls >&2; return 1 ;;
1815 esac
1816 s busctl call org.freedesktop.resolve1 /org/freedesktop/resolve1 org.freedesktop.resolve1.Manager SetLinkDNSOverTLS is $link no
1817 }
1818
1819 vpnoff() {
1820 [[ $1 ]] || { echo need arg; return 1; }
1821 if [[ -e /lib/systemd/system/openvpn-client@.service ]]; then
1822 local vpn_service=openvpn-client
1823 else
1824 local vpn_service=openvpn
1825 fi
1826 sudo systemctl stop $vpn_service@$1
1827 }
1828 vpnoffc() { # vpn off client
1829 ser stop openvpn-client-tr@client
1830 }
1831 vpnc() {
1832 ser start openvpn-client-tr@client
1833 }
1834
1835
1836 vspicy() { # usage: VIRSH_DOMAIN
1837 # connect to vms made with virt-install
1838 spicy -p $(sudo virsh dumpxml "$1"|grep "<graphics.*type='spice'"|\
1839 sed -r "s/.*port='([0-9]+).*/\1/")
1840 }
1841
1842 wian() {
1843 cat-new-files /m/4e/INBOX/new
1844 }
1845
1846 wtr() { curl wttr.in/boston; }
1847
1848 xevkb() { xev -event keyboard; }
1849
1850 # * misc stuff
1851
1852 vrun() {
1853 printf "running: %s\n" "$*"
1854 "$@"
1855 }
1856
1857 f=/a/f/ansible-configs/files/common/etc/fsf-workstation-bashrc.sh
1858 if [[ -e $f ]]; then
1859 # shellcheck disable=SC1090
1860 source $f
1861 fi
1862
1863
1864
1865
1866 reset-konsole() {
1867 # we also have a file in /a/c/...konsole...
1868 local f=$HOME/.config/konsolerc
1869 setini DefaultProfile profileian.profile "Desktop Entry" $f
1870 setini Favorites profileian.profile "Favorite Profiles" $f
1871 setini ShowMenuBarByDefault false KonsoleWindow $f
1872 setini TabBarPosition Top TabBar $f
1873 }
1874
1875 reset-sakura() {
1876 while read -r k v; do
1877 # shellcheck disable=SC2154
1878 setini $k $v sakura /a/c/subdir_files/.config/sakura/sakura.conf
1879 done <<'EOF'
1880 colorset1_back rgb(33,37,39)
1881 less_questions true
1882 audible_bell No
1883 visible_bell No
1884 disable_numbered_tabswitch true
1885 scroll_lines 10000000
1886 scrollbar true
1887 EOF
1888 }
1889
1890 reset-xscreensaver() {
1891 # except for spash, i set these by setting gui options in
1892 # xscreensaver-command -demo
1893 # then finding the corresponding option in .xscreensaver
1894 # spash, i happened to notice in .xscreensaver
1895 #
1896 # dpmsOff, monitor doesnt come back on using old free software supported nvidia card
1897 cat > /home/iank/.xscreensaver <<'EOF'
1898 mode: blank
1899 dpmsEnabled: True
1900 dpmsStandby: 0:07:00
1901 dpmsSuspend: 0:08:00
1902 dpmsOff: 0:00:00
1903 timeout: 0:05:00
1904 lock: True
1905 lockTimeout: 0:06:00
1906 splash: False
1907 EOF
1908
1909 }
1910
1911
1912 # * stuff that makes sense to be at the end
1913 if [[ "$SUDOD" ]]; then
1914 # allow failure, for example if we are sudoing into a user with diffferent/lesser permissions.
1915 cd "$SUDOD" ||:
1916 unset SUDOD
1917 elif [[ -d /a ]] && [[ $PWD == "$HOME" ]] && [[ $- == *i* ]]; then
1918 cd /a
1919 fi
1920
1921
1922
1923
1924 # for mitmproxy to get a newer python.
1925 # commented until i want to use it because it
1926 # noticably slows bash startup
1927 #
1928
1929 mypyenvinit () {
1930 if [[ $EUID == 0 || ! -e ~/.pyenv/bin ]]; then
1931 echo "error: dont be root. make sure pyenv is installed"
1932 return 1
1933 fi
1934 export PATH="$HOME/.pyenv/bin:$PATH"
1935 eval "$(pyenv init -)"
1936 eval "$(pyenv virtualenv-init -)"
1937 }
1938
1939
1940 export GOPATH=$HOME/go
1941 path-add $GOPATH/bin
1942 path-add /usr/local/go/bin
1943
1944 # I have the git repo and a release. either one should work.
1945 # I have both because I was trying to solve an issue that
1946 # turned out to be unrelated.
1947 # ARDUINO_PATH=/a/opt/Arduino/build/linux/work
1948 export ARDUINO_PATH=/a/opt/arduino-1.8.15
1949 export KALEIDOSCOPE_DIR=/a/opt/Kaleidoscope
1950
1951 # They want to be added to the start, but i think
1952 # that should be avoided unless we really need it.
1953 path-add --end ~/.npm-global
1954
1955
1956 path-add --end $HOME/.cargo/bin
1957
1958 if type -P rg &>/dev/null; then
1959 # --no-messages because of annoying errors on broken symlinks
1960 rg() { command rg --no-messages -L -i -M 300 --no-ignore "$@" || return $?; }
1961 #fails if not exist. ignore
1962 complete -r rg 2>/dev/null ||:
1963 else
1964 alias rg=grr
1965 fi
1966
1967
1968
1969 # taken from default changes to bashrc and bash_profile
1970 path-add --end --ifexists $HOME/.rvm/bin
1971 # also had ruby bin dir, but moved that to environment.sh
1972 # so its included in overall env
1973
1974
1975 export BASEFILE_DIR=/a/bin/fai-basefiles
1976
1977 #export ANDROID_HOME=/a/opt/android-home
1978 # https://f-droid.org/en/docs/Installing_the_Server_and_Repo_Tools/
1979 #export USE_SDK_WRAPPER=yes
1980 #PATH=$PATH:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools
1981
1982 # didnt get drush working, if I did, this seems like the
1983 # only good thing to include for it.
1984 # Include Drush completion.
1985 # if [ -f "/home/ian/.drush/drush.complete.sh" ] ; then
1986 # source /home/ian/.drush/drush.complete.sh
1987 # fi
1988
1989
1990 # best practice
1991 unset IFS
1992
1993 # https://wiki.archlinux.org/index.php/Xinitrc#Autostart_X_at_login
1994 # i added an extra condition as gentoo xorg guide says depending on
1995 # $DISPLAY is fragile.
1996 if [[ ! $DISPLAY && $XDG_VTNR == 1 ]] && shopt -q login_shell && isarch; then
1997 exec startx
1998 fi
1999
2000
2001 # ensure no bad programs appending to this file will have an affect
2002 return 0