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