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