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