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