minor fixes and 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 s ssh bow DISPLAY=:0 scrot /tmp/oegu.jpg
119 s scp bow:/tmp/oegu.jpg /t
120 s 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
1049 for (( i=0; i<60; i++ )); do
1050 day=$( date +%F -d @$((EPOCHSECONDS - 86400*i )) )
1051 date "+%a %b %d" -d @$((EPOCHSECONDS - 86400*i )) | tr '\n' ' '
1052 /a/opt/timetrap/bin/t d -ftotal -s $day -e $day all -m '^w|lunch$'
1053 done
1054 }
1055 to() { t out -a "$@"; }
1056 ti() { t in -a "$@"; }
1057 tl() {
1058 to "$*"
1059 t s lunch
1060 t in -a "$*"
1061 m t out -a $(date +%F.%T -d @$(( $(date -d "$(echo $*|sed 's/[_.]/ /g')" +%s) + 60*45 )) )
1062 t s w
1063 }
1064
1065 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}' ; }
1066
1067 idea() {
1068 /a/opt/idea-IC-163.7743.44/bin/idea.sh "$@" &r
1069 }
1070
1071 ilogs() {
1072 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"
1073 }
1074
1075 ilog() {
1076 chan=${1:-#fsfsys}
1077 # use * instead of -r since that does sorted order
1078 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
1079 }
1080
1081 o() {
1082 if type gio &> /dev/null ; then
1083 gio open "$@"
1084 elif type gvfs-open &> /dev/null ; then
1085 gvfs-open "$@"
1086 else
1087 xdg-open "$@"
1088 fi
1089 # another alternative is run-mailcap
1090 }
1091 ccomp xdg-open o
1092
1093 # jfilter() {
1094 # grep -Evi -e "^(\S+\s+){4}(sudo|sshd|cron)\[\S*:" \
1095 # -e "^(\S+\s+){4}systemd\[\S*: (starting|started) (btrfsmaintstop|dynamicipupdate|spamd dns bug fix cronjob|rss2email)\.*$"
1096 # }
1097 # jtail() {
1098 # journalctl -n 10000 -f "$@" | jfilter
1099 # }
1100 # jr() { journalctl "$@" | jfilter | less ; }
1101 # jrf() { journalctl -n 200 -f "$@" | jfilter; }
1102
1103 jr() { journalctl "$@" ; }
1104 jrf() { journalctl -n 200 -f "$@" ; }
1105
1106
1107 ccomp journalctl jtail jr jrf
1108
1109 kff() { # keyboardio firmware flash. you must hold down the tilde key
1110 pushd /a/opt/Model01-Firmware
1111 # if we didn't want this yes hack, then remove "shell read" from
1112 # /a/opt/Kaleidoscope/etc/makefiles/sketch.mk
1113 yes $'\n' | VERBOSE=1 make flash
1114 popd
1115 }
1116
1117 wgkey() {
1118 local umask_orig name
1119 if (( $# != 1 )); then
1120 e expected 1 arg >&2
1121 return 1
1122 fi
1123 name=$1
1124 umask_orig=$(umask)
1125 umask 0077
1126 wg genkey | tee $name-priv.key | wg pubkey > $name-pub.key
1127 umask $umask_orig
1128 }
1129 wghole() {
1130 if (( $# != 2 )); then
1131 e expected 2 arg of hostname, ip suffix >&2
1132 return 1
1133 fi
1134 local host ipsuf umask_orig
1135 host=$1
1136 ipsuf=$2
1137 mkdir -p /p/c/machine_specific/$host/filesystem/etc/wireguard
1138 cd /p/c/machine_specific/$host/filesystem/etc/wireguard
1139 umask_orig=$(umask)
1140 umask 0077
1141 wg genkey | tee hole-priv.key | wg pubkey > hole-pub.key
1142 cat >wghole.conf <<EOF
1143 [Interface]
1144 # contents hole-priv.key
1145 PrivateKey = $(cat hole-priv.key)
1146 ListenPort = 1194
1147 Address = 10.8.0.$ipsuf/24
1148 # https://dev.to/tangramvision/what-they-don-t-tell-you-about-setting-up-a-wireguard-vpn-1h2g
1149 # ||: makes the systemd service not fail due to the failed command
1150 PostUp = ping -c1 10.8.0.1 ||:
1151
1152 [Peer]
1153 # li. called wgmail on that server
1154 PublicKey = CTFsje45qLAU44AbX71Vo+xFJ6rt7Cu6+vdMGyWjBjU=
1155 AllowedIPs = 10.8.0.0/24
1156 Endpoint = 72.14.176.105:1194
1157 PersistentKeepalive = 25
1158 EOF
1159 umask $umask_orig
1160 # old approach. systemd seems to work fine and cleaner.
1161 rm -f ../network/interfaces.d/wghole
1162 cedit -q $host /p/c/machine_specific/li/filesystem/etc/wireguard/wgmail.conf <<EOF || [[ $? == 1 ]]
1163 [Peer]
1164 PublicKey = $(cat hole-pub.key)
1165 AllowedIPs = 10.8.0.$ipsuf/32
1166 EOF
1167 cd - >/dev/null
1168 }
1169
1170
1171 mns() { # mount namespace
1172 ns=$1
1173 shift
1174 s mkdir -p /root/mount_namespaces
1175 if ! sudo mountpoint /root/mount_namespaces >/dev/null; then
1176 m sudo mount --bind /root/mount_namespaces /root/mount_namespaces
1177 fi
1178 m sudo mount --make-private /root/mount_namespaces
1179 if [[ ! -e /root/mount_namespaces/$ns ]]; then
1180 m sudo touch /root/mount_namespaces/$ns
1181 fi
1182 if ! sudo mountpoint /root/mount_namespaces/$ns >/dev/null; then
1183 m sudo unshare --propagation slave --mount=/root/mount_namespaces/$ns /bin/true
1184 fi
1185 m sudo -E /usr/bin/nsenter --mount=/root/mount_namespaces/$ns "$@"
1186 }
1187
1188 mnsr() { # mns run
1189 local ns=$1
1190 shift
1191 mns $ns sudo -u iank -E env "PATH=$PATH" "$@"
1192 }
1193
1194 mnsnonet() {
1195 ns=$1
1196 lomh
1197 if ! s ip netns list | grep -Fx nonet &>/dev/null; then
1198 s ip netns add nonet
1199 fi
1200 mns $ns --net=/var/run/netns/nonet sudo -E -u iank /bin/bash
1201 lomh
1202 }
1203
1204
1205 lom() {
1206 # l = the loopback device
1207 local l base
1208 if [[ $1 == /* ]]; then
1209 base=${1##*/}
1210 fs_file=$1
1211 if mns $base mountpoint -q /mnt/$base; then
1212 return 0
1213 fi
1214 l=$(losetup -j $fs_file | sed -rn 's/^([^ ]+): .*/\1/p' | head -n1 ||:)
1215 if [[ ! $l ]]; then
1216 l=$(sudo losetup -f)
1217 m sudo losetup $l $fs_file
1218 fi
1219 if ! sudo cryptsetup status /dev/mapper/$base &>/dev/null; then
1220 if ! sudo cryptsetup luksOpen $l $base; then
1221 m sudo losetup -d $l
1222 return 1
1223 fi
1224 fi
1225 m sudo mkdir -p /mnt/$base
1226 m mns $base mount /dev/mapper/$base /mnt/$base
1227 m mns $base chown $USER:$USER /mnt/$base
1228 lomh
1229 else
1230 base=$1
1231 if mns $base mountpoint /mnt/$base &>/dev/null; then
1232 m mns $base umount /mnt/$base
1233 fi
1234 if sudo cryptsetup status /dev/mapper/$base &>/dev/null; then
1235 if ! m sudo cryptsetup luksClose /dev/mapper/$base; then
1236 echo lom: failed cryptsetup luksClose /dev/mapper/$base
1237 return 1
1238 fi
1239 fi
1240 l=$(losetup -l --noheadings | awk '$6 ~ /\/'$base'$/ {print $1}')
1241 if [[ $l ]]; then
1242 m sudo losetup -d $l
1243 else
1244 echo lom: warning: no loopback device found
1245 fi
1246 fi
1247 }
1248
1249 # mu personality. for original, just run mp. for 2, run mp 2.
1250 # this is partly duplicated in mail-setup
1251 mp() {
1252 local dead=false
1253 for s in {1..5}; do
1254 if ! killall mu; then
1255 dead=true
1256 break
1257 fi
1258 sleep 1
1259 done
1260 if ! $dead; then
1261 echo error: mu not dead
1262 m psg mu
1263 return 1
1264 fi
1265 suf=$1
1266 set -- /m/mucache ~/.cache/mu /m/.mu ~/.config/mu
1267 while (($#)); do
1268 target=$1$suf
1269 f=$2
1270 shift 2
1271 if [[ -e $f && ! -L $f ]]; then
1272 m rm -rf $f
1273 fi
1274 m ln -sf -T $target $f
1275 done
1276 }
1277
1278 # maildir enable
1279 mdenable() {
1280 local md dst ln_path src two
1281
1282 two=false
1283 case $1 in
1284 -2) two=true shift ;;
1285 esac
1286
1287 for md; do
1288 src=
1289 if $two; then
1290 dst=/m/4e2/$md
1291 else
1292 dst=/m/4e/$md
1293 fi
1294
1295 ln_path=/m/md/$md
1296 for d in /m/md/$md /m/4e2/$md; do
1297 if [[ -d $d && ! -L $d ]]; then
1298 src=$d
1299 break
1300 fi
1301 done
1302 if [[ ! $src ]]; then
1303 echo "error: could not find $md" >&2
1304 return 1
1305 fi
1306 m mv -T $src $dst
1307 m ln -sf -T $dst $ln_path
1308 done
1309 }
1310 md2enable() {
1311 mdenable -2 "$@"
1312 }
1313 mddisable() {
1314 local md=$1
1315 dst=/m/md/$md
1316
1317 ### begin copied from mdenable, but different d ###
1318 for d in /m/4e/$md /m/4e2/$md; do
1319 if [[ -d $d && ! -L $d ]]; then
1320 src=$d
1321 break
1322 fi
1323 done
1324 if [[ ! $src ]]; then
1325 echo "error: could not find $md" >&2
1326 return 1
1327 fi
1328 ### end copy from mdenable ###
1329
1330 if [[ -L $dst ]]; then m rm $dst; fi
1331 m mv -T $src $dst
1332 }
1333
1334
1335 mdt() {
1336 markdown "$1" >/tmp/mdtest.html
1337 firefox /tmp/mdtest.html
1338 }
1339
1340 mo() { xset dpms force off; } # monitor off
1341
1342 mpvgpu() {
1343 # seems to be the best gpu decoding on my nvidia 670.
1344 # vlc gets similar or better framerate, but is much darker output on my test movie at least.
1345
1346
1347 case $HOSTNAME in
1348 kd)
1349 echo 0f | sudo tee -a /sys/kernel/debug/dri/0/pstate
1350 ;;
1351 esac
1352 # going back to the default slow clock, and slower fan:
1353 # echo 07 | sudo tee -a /sys/kernel/debug/dri/0/pstate
1354 if [[ $DISPLAY ]]; then
1355 mpv --vo=vdpau --hwdec=auto "$@"
1356 else
1357 # waylandvk seems to work the same
1358 mpv --gpu-context=wayland --hwdec=auto
1359 fi
1360 }
1361
1362 mpvd() {
1363 mpv --profile=d "$@";
1364 }
1365 # mpv all media files in . or $1
1366 mpvm() {
1367 local -a extensions arg
1368 # get page source of https://en.wikipedia.org/w/index.php?title=Video_file_format&action=edit
1369 # into /a/x.log, then
1370 # grep '^| *\.' /a/x.log | sed 's/| *//;s/,//g'
1371 extensions=(
1372 .webm
1373 .mkv
1374 .flv
1375 .flv
1376 .vob
1377 .ogv .ogg
1378 .drc
1379 .gif
1380 .gifv
1381 .mng
1382 .avi
1383 .MTS .M2TS .TS
1384 .mov .qt
1385 .wmv
1386 .yuv
1387 .rm
1388 .rmvb
1389 .viv
1390 .asf
1391 .amv
1392 .mp4 .m4p .m4v
1393 .mpg .mp2 .mpeg .mpe .mpv
1394 .mpg .mpeg .m2v
1395 .m4v
1396 .svi
1397 .3gp
1398 .3g2
1399 .mxf
1400 .roq
1401 .nsv
1402 )
1403 arg=("(" -iname "*${extensions[0]}")
1404 for (( i=1 ; i < ${#extensions[@]}; i++ )); do
1405 arg+=(-o -iname "*${extensions[i]}")
1406 done
1407 arg+=(")")
1408 dir=${1:-.}
1409 # debug:
1410 #find $dir "${arg[@]}" -size +200k
1411 find $dir "${arg[@]}" -size +200k -exec mpv --profile=d '{}' +
1412 }
1413 mpvs() {
1414 mpv --profile=s "$@";
1415 }
1416
1417 myirc() {
1418 if [[ ! $1 ]]; then
1419 set -- fsf-office
1420 fi
1421 local d1 d2
1422 d=( /var/lib/znc/moddata/log/iank/{freenode,libera} )
1423 # use * instead of -r since that does sorted order
1424 ssh root@iankelling.org "for f in ${d[@]}; do cd \$f/#$1; grep '\<iank.*' *; done" | cut --complement -c12-16
1425 }
1426 mypidgin() {
1427 c /p/c/.purple/logs/jabber/iank@fsf.org/office@conference.fsf.org.chat
1428 for x in *.html; do html2text -o ${x%.html}.txt $x; done;
1429 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}'
1430 }
1431 allmyirc() {
1432 local d
1433 d=/var/lib/znc/moddata/log/iank/freenode
1434 ssh root@iankelling.org "cd $d; find . -mtime -60 -type f -exec grep '\<iank.*' {} +" | sed -r 's,^..([^/]*)/(.{11})(.{5})(.{8}).,\2\4 \1,' | sort
1435 }
1436
1437 mygajim() {
1438 local time time_sec time_pretty
1439 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
1440 case $time in
1441 16*) : ;;
1442 *) continue ;;
1443 esac
1444 if ! time_pretty=$(date +%F.%R -d @$time); then
1445 echo bad time: $time
1446 return 1
1447 fi
1448 echo $time_pretty "$l"
1449 time_sec=${time%%.*}
1450 # only look at the last 18 days. generally just use this for timesheet.
1451 if (( time_sec < EPOCHSECONDS - 60 * 60 * 24 * 18 )); then break; fi
1452 done
1453 }
1454
1455 allmygajim() {
1456 sqlite3 -separator ' ' /p/c/subdir_files/.local/share/gajim/logs.db "select time, message from logs where contact_name = 'iank'" | less
1457 }
1458
1459 gajlogs() {
1460 sqlite3 -separator ' ' /p/c/subdir_files/.local/share/gajim/logs.db "select time, message from logs" | less
1461 }
1462
1463 net-dev-info() {
1464 e "lspci -nnk|gr -iA2 net"
1465 lspci -nnk|gr -iA2 net
1466 hr
1467 e "s lshw -C network"
1468 hr
1469 sudo lshw -C network
1470 }
1471
1472 nk() {
1473 ser stop NetworkManager
1474 ser disable NetworkManager
1475 ser stop NetworkManager-wait-online.service
1476 ser disable NetworkManager-wait-online.service
1477 ser stop dnsmasq
1478 sudo resolvconf -d NetworkManager
1479 # ser start dnsmasq
1480 sudo ifup br0
1481 }
1482 ngo() {
1483 sudo ifdown br0
1484 ser start NetworkManager
1485 sleep 4
1486 sudo nmtui-connect
1487 }
1488
1489 otp() {
1490 oathtool --totp -b "$*" | xclip -selection clipboard
1491 }
1492 j() {
1493 "$@" |& pee "xclip -r -selection clipboard"
1494 }
1495
1496
1497 pakaraoke() {
1498 # from http://askubuntu.com/questions/456021/remove-vocals-from-mp3-and-get-only-instrumentals
1499 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
1500 }
1501
1502 pfind() { #find *$1* in $PATH
1503 [[ $# != 1 ]] && { echo requires 1 argument; return 1; }
1504 local pathArray
1505 IFS=: pathArray=($PATH); unset IFS
1506 find "${pathArray[@]}" -iname "*$1*"
1507 }
1508
1509 pick-trash() {
1510 # trash-restore lists everything that has been trashed at or below CWD
1511 # This picks out files just in CWD, not subdirectories,
1512 # which also match grep $1, usually use $1 for a time string
1513 # which you get from running restore-trash once first
1514 local name x ask
1515 local nth=1
1516 # last condition is to not ask again for ones we skipped
1517 while name="$( echo | restore-trash | gr "$PWD/[^/]\+$" | gr "$1" )" \
1518 && [[ $name ]] && (( $(wc -l <<<"$name") >= nth )); do
1519 name="$(echo "$name" | head -n $nth | tail -n 1 )"
1520 read -r -p "$name [Y/n] " ask
1521 if [[ ! $ask || $ask == [Yy] ]]; then
1522 x=$( echo "$name" | gr -o "^\s*[0-9]*" )
1523 echo $x | restore-trash > /dev/null
1524 elif [[ $ask == [Nn] ]]; then
1525 nth=$((nth+1))
1526 else
1527 return
1528 fi
1529 done
1530 }
1531
1532
1533 pub() {
1534 rld /a/h/_site/ li:/var/www/iankelling.org/html
1535 }
1536
1537
1538 pumpa() {
1539 # fixes the menu bar in xmonad. this won\'t be needed when xmonad
1540 # packages catches up on some changes in future (this is written in
1541 # 4/2017)
1542 #
1543 # geekosaur: so youll want to upgrade to xmonad 0.13 or else use a
1544 # locally modified XMonad.Hooks.ManageDocks that doesnt set the
1545 # work area; turns out it\'s impossible to set correctly if you are
1546 # not a fully EWMH compliant desktop environment
1547 #
1548 # geekosaur: chrome shows one failure mode, qt/kde another, other
1549 # gtk apps a third, ... I came up with a setting that works for me
1550 # locally but apparently doesnt work for others, so we joined the
1551 # other tiling window managers in giving up on setting it at all
1552 #
1553 xprop -root -remove _NET_WORKAREA
1554 command pumpa & r
1555 }
1556
1557 # reviewboard, used at my old job
1558 #rbpipe() { rbt post -o --diff-filename=- "$@"; }
1559 #rbp() { rbt post -o "$@"; }
1560
1561 rebr() {
1562 sudo ifdown br0
1563 sudo ifup br0
1564 }
1565
1566
1567 r2e() { command r2e -d /p/c/rss2email.json -c /p/c/rss2email.cfg "$@"; }
1568 # only run on MAIL_HOST. simpler to keep this on one system.
1569 r2eadd() { # usage: name url
1570 # initial setup of rss2email:
1571 # r2e new r2e@iankelling.org
1572 # that initializes files, and sets default email.
1573 # symlink to the config doesnt work, so I copied it to /p/c
1574 # and then use cli option to specify explicit path.
1575 # Only option changed from default config is to set
1576 # force-from = True
1577 #
1578 # or else for a few feeds, the from address is set by the feed, and
1579 # if I fail delivery, then I send a bounce message to that from
1580 # address, which makes me be a spammer.
1581
1582 r2e add $1 "$2" $1@r2e.iankelling.org
1583 # get up to date and dont send old entries now:
1584 r2e run --no-send $1
1585 }
1586
1587 rspicy() { # usage: HOST DOMAIN
1588 # connect to spice vm remote host. use vspicy for local host
1589 local port
1590 # shellcheck disable=SC2087
1591 port=$(ssh $1<<EOF
1592 sudo virsh dumpxml $2|grep "<graphics.*type='spice'" | \
1593 sed -rn "s/.*port='([0-9]+).*/\1/p"
1594 EOF
1595 )
1596 if [[ $port ]]; then
1597 spicy -h $1 -p $port
1598 else
1599 echo "error: no port found. check that the domain is running."
1600 fi
1601 }
1602
1603
1604 scssl() {
1605 # s gem install scss-lint
1606 pushd /a/opt/thoughtbot-guides
1607 git pull --stat
1608 popd
1609 scss-lint -c /a/opt/thoughtbot-guides/style/sass/.scss-lint.yml "$@"
1610 }
1611
1612 skbrc() {
1613 sk -e 2120,245 /b/ds/brc /b/ds/brc2
1614 }
1615
1616 skaraoke() {
1617 local tmp out
1618 out=${2:-${1%.*}.sh}
1619 tmp=$(mktemp -d)
1620 script -t -c "mpv --no-config --no-resume-playback --no-terminal --no-audio-display '$1'" $tmp/typescript 2>$tmp/timing
1621 # todo, the current sleep seems pretty good, but it
1622 # would be nice to have an empirical measurement, or
1623 # some better wait to sync up.
1624 #
1625 # note: --loop-file=no prevents it from hanging if you have that
1626 # set to inf the mpv config.
1627 # --loop=no prevents it from exit code 3 due to stdin if you
1628 # had it set to inf in mpv config.
1629 #
1630 # args go to mpv, for example --volume=80, 50%
1631 cat >$out <<EOFOUTER
1632 #!/bin/bash
1633 trap "trap - TERM && kill 0" INT TERM ERR; set -e
1634 ( sleep .2; scriptreplay <( cat <<'EOF'
1635 $(cat $tmp/timing)
1636 EOF
1637 ) <( cat <<'EOF'
1638 $(cat $tmp/typescript)
1639 EOF
1640 ))&
1641 base64 -d - <<'EOF'| mpv --loop=no --loop-file=no --no-terminal --no-audio-display "\$@" -
1642 $(base64 "$1")
1643 EOF
1644 kill 0
1645 EOFOUTER
1646 rm -r $tmp
1647 chmod +x $out
1648 }
1649
1650 smeld() { # ssh meld usage host1 host2 file
1651 meld <(ssh $1 cat $3) <(ssh $2 cat $3)
1652 }
1653
1654 spd() {
1655 PATH=/usr/local/spdhackfix:$PATH command spd "$@"
1656 }
1657
1658 spamf() { # spamtest on FILE
1659 local spamcpre spamdpid
1660
1661 if (( $# != 1 )); then
1662 e spamtest error: expected 1 arg, filename >&2
1663 return 1
1664 fi
1665
1666 spamdpid=$(systemctl status spamassassin| sed -n '/^ *Main PID:/s/[^0-9]//gp')
1667 spamcpre="nsenter -t $spamdpid -n -m"
1668 s $spamcpre sudo -u Debian-exim spamassassin -t --cf='score PYZOR_CHECK 0' <"$1"
1669 }
1670
1671
1672 # mail related
1673 testmail() {
1674 declare -gi _seq; _seq+=1
1675 echo "test body" | m mail -s "test mail from $HOSTNAME, $_seq" "${@:-root@localhost}"
1676 # for testing to send from an external address, you can do for example
1677 # -fian@iank.bid -aFrom:ian@iank.bid web-6fnbs@mail-tester.com
1678 # note in exim, you can retry a deferred message
1679 # s exim -M MSG_ID
1680 # MSG_ID is in /var/log/exim4/mainlog, looks like 1ccdnD-0001nh-EN
1681 }
1682
1683 # to test sieve, use below command. for fsf mail, see offlineimap-sync script
1684 # make modifications, then copy to live file, use -eW to actually modify mailbox
1685 #
1686 # Another option is to use sieve-test SCRIPT MAIL_FILE. note,
1687 # sieve-test doesnt know about envelopes, Im not sure if sieve-filter does.
1688
1689 # sieve with output filter. arg is mailbox, like INBOX.
1690 # This depends on dovecot conf, notably mail_location in /etc/dovecot/conf.d/10-mail.conf
1691
1692 # always run this first, edit the test files, then run the following
1693 testsieve() {
1694 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
1695 }
1696 runsieve() {
1697 c ~/sieve; cp personal{test,}.sieve; cp lists{test,}.sieve; cp personalend{test,}.sieve
1698 sieve-filter -eWv ~/sieve/maintest.sieve ${1:-INBOX} delete &> /tmp/testsieve.log
1699 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
1700 }
1701
1702 # usage:
1703 # alertme SUBJECT
1704 # printf "subject\nbody\n" | alertme
1705 alertme() {
1706 if [[ -t 0 ]]; then
1707 exim -t <<EOF
1708 From: alertme@b8.nz
1709 To: alerts@iankelling.org
1710 Subject: $*
1711 EOF
1712 else
1713 read sub
1714 { cat <<EOF
1715 From: alertme@b8.nz
1716 To: alerts@iankelling.org
1717 Subject: $sub
1718
1719 EOF
1720 cat
1721 } | exim -t
1722 fi
1723 }
1724 daylertme() {
1725 if [[ -t 0 ]]; then
1726 exim -t <<EOF
1727 From: alertme@b8.nz
1728 To: daylert@iankelling.org
1729 Subject: $*
1730 EOF
1731 else
1732 read sub
1733 { cat <<EOF
1734 From: alertme@b8.nz
1735 To: daylert@iankelling.org
1736 Subject: $sub
1737
1738 EOF
1739 cat
1740 } | exim -t
1741 fi
1742 }
1743
1744 # alert when a page goes live.
1745 alert200() {
1746 local quiet url tmpdir
1747 quiet=false
1748 case $1 in
1749 # dont send a diff of the html. some html is not very readable
1750 -q) quiet=true
1751 shift
1752 ;;
1753 esac
1754 url="$1"
1755 tmpdir="$(mktemp -d)"
1756 cd $tmpdir
1757 while true; do
1758 if wget -q "$url"; then
1759 if $quiet; then
1760 echo | daylert 200
1761 else
1762 alertme $tmpdir
1763 fi
1764 fi
1765 sleep $(( 120 + RANDOM % 300 ))
1766 done
1767 }
1768
1769 # alert on changes to a webpage (just the base page that curl gets)
1770 # usage: weblert URL [SUBJECT...]
1771 weblert() {
1772 local u old new quiet
1773 quiet=false
1774 case $1 in
1775 # dont send a diff of the html. some html is not very readable
1776 -q) quiet=true
1777 shift
1778 ;;
1779 esac
1780 u="$1"
1781 shift
1782 subject="${*:-weblert}"
1783 old=$(curl -s "$u") ||:
1784 while true; do
1785 new=$(curl -s "$u") ||:
1786 if [[ $old && $new ]]; then
1787 if [[ $new != "$old" ]]; then
1788 if $quiet; then
1789 echo | daylertme "$subject"
1790 else
1791 diff <(printf "%s\n" "$old") <(printf "%s\n" "$new") | daylertme "$subject" ||:
1792 fi
1793 fi
1794 old="$new"
1795 fi
1796 sleep $(( 60 + RANDOM % 120 ))
1797 done
1798 }
1799
1800 torshell() {
1801 # per man torsocks
1802 source `type -p torsocks` on
1803 }
1804
1805 eless2() {
1806 less /var/log/exim4/mymain
1807 }
1808
1809
1810 # mail related
1811 testexim() {
1812 # testmail above calls sendmail, which is a link to exim/postfix.
1813 # its docs dont say a way of adding an argument
1814 # to sendmail to turn on debug output. We could make a wrapper, but
1815 # that is a pain. Exim debug args are documented here:
1816 # http://www.exim.org/exim-html-current/doc/html/spec_html/ch-the_exim_command_line.html
1817 #
1818 # http://www.exim.org/exim-html-current/doc/html/spec_html/ch-building_and_installing_exim.html
1819 # note, for exim daemon, you can turn on debug options by
1820 # adding -d, etc to COMMONOPTIONS in
1821 # /etc/default/exim4
1822 #
1823 # to specify recipients other than those in to, cc, bcc, you can use the cli args, eg:
1824 # exim -t 'test@zroe.org, t2@zroe.org' <<'EOF'
1825 #
1826 # -t = get recipient from header
1827 exim -d -t <<EOF
1828 From: root@$(hostname -f)
1829 To: root@$(hostname -f)
1830 Subject: test2
1831
1832 This is a test message.
1833 EOF
1834 }
1835
1836 # toggle keyboard
1837 tk() {
1838 # based on
1839 # https://askubuntu.com/questions/160945/is-there-a-way-to-disable-a-laptops-internal-keyboard
1840 id=$(xinput --list --id-only 'AT Translated Set 2 keyboard')
1841 if xinput list | grep -F '∼ AT Translated Set 2 keyboard' &>/dev/null; then
1842 echo enabling keyboard
1843 # find the first slave keyboard number, they are all the same in my output.
1844 # if they werent, worst case we would need to save the slave number somewhere
1845 # when it got disabled.
1846 slave=$(xinput list | sed -n 's/.*slave \+keyboard (\([0-9]*\)).*/\1/p' | head -n1)
1847 xinput reattach $id $slave
1848 else
1849 xinput float $id
1850 fi
1851 }
1852
1853 tm() {
1854 # timer in minutes
1855 # --no-config
1856 (sleep $(calc "$* * 60") && mpv --no-config --volume 50 /a/bin/data/alarm.mp3) > /dev/null 2>&1 &
1857 }
1858
1859 trg() { transmission-remote-gtk & r; }
1860 trc() {
1861 # example, set global upload limit to 100 kilobytes:
1862 # trc -u 100
1863 TR_AUTH=":$(jq -r .profiles[0].password ~/.config/transmission-remote-gtk/config.json)" transmission-remote transmission.lan -ne "$@"
1864 }
1865
1866 trysleep() {
1867 retries="$1"
1868 sleepsecs="$2"
1869 shift 2
1870 for (( i=0; i < retries - 1; i++ )); do
1871 if "$@"; then
1872 return 0
1873 fi
1874 sleep $sleepsecs
1875 done
1876 "$@"
1877 }
1878
1879
1880 tu() {
1881 local s
1882 if [[ -e $1 && ! -w $1 || ! -w $(dirname "$1") ]]; then
1883 s=s;
1884 fi
1885 # full path for using in some initial setup steps
1886 $s /a/exe/teeu "$@"
1887 }
1888
1889 enn() {
1890 local ecmd pid
1891
1892 ecmd="/usr/sbin/exim4 -C /etc/exim4/my.conf"
1893 if ip a show veth1-mail &>/dev/null; then
1894 s $ecmd "$@"
1895 return
1896 fi
1897 pid=$(pgrep -f "/usr/sbin/exim4 -bd -q30m -C /etc/exim4/my.conf"|h1)
1898 m s nsenter -t $pid -n -m $ecmd "$@"
1899 }
1900
1901 # get pid of systemd service
1902 servicepid() {
1903 local pid unit dir
1904 unit="$1"
1905 pid=$(systemctl show --property MainPID --value "$unit")
1906 case $pid in
1907 [1-9]*) : ;;
1908 *)
1909
1910 dir=/sys/fs/cgroup/system.slice
1911 if [[ ! -d $dir ]]; then
1912 # t10 and older directory.
1913 dir=/sys/fs/cgroup/systemd/system.slice
1914 fi
1915
1916 # 0 or empty. This file includes the MainPid, so I expect we
1917 # could just get this in the first place, but i don't know if that
1918 # is always the case.
1919 pid=$(head -n1 $dir/${unit%.service}.service/cgroup.procs)
1920 ;;
1921 esac
1922 if [[ $pid ]]; then
1923 printf "%s\n" "$pid"
1924 else
1925 return 1
1926 fi
1927 }
1928
1929 sdnbash() { # systemd namespace bash
1930 local unit pid
1931 if (( $# != 1 )); then
1932 echo $0: error wrong number of args >&2
1933 return 1
1934 fi
1935 unit=$1
1936 pid=$(servicepid $unit)
1937 m sudo nsenter -t $pid -n -m sudo -u $USER -i bash
1938 }
1939
1940 sdnbashroot() { # systemd namespace bash
1941 local unit pid
1942 if (( $# != 1 )); then
1943 echo $0: error wrong number of args >&2
1944 return 1
1945 fi
1946 unit=$1
1947 pid=$(servicepid $unit)
1948 m sudo nsenter -t $pid -n -m bash
1949 }
1950
1951
1952 sdncmd() { # systemd namespace cmd
1953 local unit pid
1954 if (( $# <= 2 )); then
1955 echo $0: error wrong number of args >&2
1956 return 1
1957 fi
1958 unit=$1
1959 shift
1960 pid=$(servicepid $unit)
1961 m sudo nsenter -t $pid -n -m sudo -u $USER -i "$@"
1962 }
1963
1964
1965 mailnnbash() {
1966 sdnbash mailnn
1967 }
1968
1969 # we use wireguard now, use mailnnbash.
1970 # mailvpnbash() {
1971 # m sudo nsenter -t $(pgrep -f "/usr/sbin/openvpn .* --config /etc/openvpn/.*mail.conf") -n -m sudo -u $USER -i bash
1972 # }
1973
1974 eximbash() {
1975 local pid
1976 pid=$(pgrep -f "/usr/sbin/exim4 -bd -q30m -C /etc/exim4/my.conf"|h1)
1977 if [[ ! $pid ]]; then
1978 echo "eximbash: failed to find exim pid. systemctl -n 30 status exim4:"
1979 systemctl status exim4
1980 fi
1981 m sudo nsenter -t $pid -n -m
1982 }
1983 spamnn() {
1984 local spamdpid
1985 spamdpid=$(systemctl show --property MainPID --value spamassassin)
1986 m sudo nsenter -t $spamdpid -n -m sudo -u Debian-exim spamassassin "$@"
1987 }
1988 unboundbash() {
1989 m sudo nsenter -t $(systemctl status unbound| sed -n '/^ *Main PID:/s/[^0-9]//gp') -n -m sudo -u $USER -i bash
1990 }
1991
1992 nmtc() {
1993 s nmtui-connect "$@"
1994 }
1995
1996 mailnncheck() {
1997 local unit pid ns mailnn
1998 # mailvpn would belong on the list if using openvpn
1999 for unit in mailnn unbound dovecot spamassassin exim4 radicale; do
2000 pid=$(servicepid $unit)
2001 echo debug: unit=$unit pid=$pid
2002 if [[ ! $pid ]]; then
2003 echo failed to find pid for unit=$unit
2004 continue
2005 fi
2006 if ! ns=$(s readlink /proc/$pid/ns/net); then
2007 echo failed to find ns for unit=$unit pid=$pid
2008 continue
2009 fi
2010 if [[ $mailnn ]]; then
2011 if [[ $ns != "$mailnn" ]]; then
2012 echo "$unit ns $ns != $mailnn"
2013 fi
2014 else
2015 mailnn=$ns
2016 fi
2017 done
2018
2019 }
2020
2021
2022 vpncmd() {
2023 m sudo -E env "PATH=$PATH" nsenter -t $(pgrep -f "/usr/sbin/openvpn .* --config /etc/openvpn/.*client.conf") -n "$@"
2024 }
2025
2026 vpni() {
2027 vpncmd sudo -u iank env "PATH=$PATH" "$@"
2028 }
2029 vpnbash() {
2030 vpncmd bash
2031 }
2032
2033
2034 vpn() {
2035 if [[ -e /lib/systemd/system/openvpn-client@.service ]]; then
2036 local vpn_service=openvpn-client
2037 else
2038 local vpn_service=openvpn
2039 fi
2040
2041 [[ $1 ]] || { echo need arg; return 1; }
2042 journalctl --unit=$vpn_service@$1 -f -n0 &
2043 # sometimes the journal doesnt open until after the vpn output
2044 # has happened. hoping this fixes that.
2045 sleep 1
2046 sudo systemctl start $vpn_service@$1
2047 # sometimes the ask-password agent does not work and needs a delay.
2048 sleep .5
2049 # https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=779240
2050 # noticed around 8-2017 after update from around stretch release
2051 # on debian testing, even though the bug is much older.
2052 sudo systemd-tty-ask-password-agent
2053 }
2054
2055 fixu() {
2056 local stats
2057 ls -lad /run/user/1000
2058 stats=$(stat -c%a-%g-%u /run/user/1000)
2059 if [[ $stats != 700-1000-1000 ]]; then
2060 m s chmod 700 /run/user/1000; m s chown iank.iank /run/user/1000
2061 fi
2062 }
2063
2064 # systemctl is-enabled / status / cat says nothing, instead theres
2065 # some obscure symlink. paths copied from man systemd.unit.
2066 # possibly also usefull, but incomplete, doesnt show units not loaded in memory:
2067 # seru list-dependencies --reverse --all UNIT
2068 sysd-deps() {
2069 local f
2070 local -a dirs search
2071 ngset
2072
2073 case $1 in
2074 u)
2075 search=(
2076 ~/.config/systemd/user.control/*
2077 $XDG_RUNTIME_DIR/systemd/user.control/*
2078 $XDG_RUNTIME_DIR/systemd/transient/*
2079 $XDG_RUNTIME_DIR/systemd/generator.early/*
2080 ~/.config/systemd/user/*
2081 /etc/systemd/user/*
2082 $XDG_RUNTIME_DIR/systemd/user/*
2083 /run/systemd/user/*
2084 $XDG_RUNTIME_DIR/systemd/generator/*
2085 ~/.local/share/systemd/user/*
2086 /usr/lib/systemd/user/*
2087 $XDG_RUNTIME_DIR/systemd/generator.late/*
2088 )
2089 ;;
2090 *)
2091 search=(
2092 /etc/systemd/system.control/*
2093 /run/systemd/system.control/*
2094 /run/systemd/transient/*
2095 /run/systemd/generator.early/*
2096 /etc/systemd/system/*
2097 /etc/systemd/systemd.attached/*
2098 /run/systemd/system/*
2099 /run/systemd/systemd.attached/*
2100 /run/systemd/generator/*
2101 /lib/systemd/system/*
2102 /run/systemd/generator.late/*
2103 )
2104 ;;
2105 esac
2106 for f in "${search[@]}"; do
2107 [[ -d $f ]] || continue
2108 case $f in
2109 *.requires|*.wants)
2110 dirs+=("$f")
2111 ;;
2112 esac
2113 done
2114 # dirs is just so we write out the directory names, ls does it when there is 2 or more dirs.
2115 case ${#dirs[@]} in
2116 1)
2117 echo "${dirs[0]}:"
2118 ll "${dirs[@]}"
2119 ;;
2120 0) : ;;
2121 *)
2122 ll "${dirs[@]}"
2123 ;;
2124 esac
2125 ngreset
2126 }
2127
2128 fixvpndns() {
2129 local link istls
2130 read _ link _ istls < <(resolvectl dnsovertls tunfsf)
2131 case $istls in
2132 yes|no) : ;;
2133 *) echo fixvpndns error: unexpected istls value: $istls >&2; return 1 ;;
2134 esac
2135 s busctl call org.freedesktop.resolve1 /org/freedesktop/resolve1 org.freedesktop.resolve1.Manager SetLinkDNSOverTLS is $link no
2136 }
2137
2138 vpnoff() {
2139 [[ $1 ]] || { echo need arg; return 1; }
2140 if [[ -e /lib/systemd/system/openvpn-client@.service ]]; then
2141 local vpn_service=openvpn-client
2142 else
2143 local vpn_service=openvpn
2144 fi
2145 sudo systemctl stop $vpn_service@$1
2146 }
2147 vpnoffc() { # vpn off client
2148 ser stop openvpn-client-tr@client
2149 }
2150 vpnc() {
2151 ser start openvpn-client-tr@client
2152 }
2153
2154
2155 vspicy() { # usage: VIRSH_DOMAIN
2156 # connect to vms made with virt-install
2157 spicy -p $(sudo virsh dumpxml "$1"|grep "<graphics.*type='spice'"|\
2158 sed -r "s/.*port='([0-9]+).*/\1/")
2159 }
2160
2161 wian() {
2162 cat-new-files /m/4e/INBOX/new
2163 }
2164
2165 wtr() { curl wttr.in/boston; }
2166
2167 xevkb() { xev -event keyboard; }
2168
2169 # * misc stuff
2170
2171 vrun() {
2172 printf "running: %s\n" "$*"
2173 "$@"
2174 }
2175
2176 f=/a/f/ansible-configs/files/common/etc/fsf-workstation-bashrc.sh
2177 if [[ -e $f ]]; then
2178 # shellcheck disable=SC1090
2179 source $f
2180 fi
2181
2182 electrum() {
2183 # https://electrum.readthedocs.io/en/latest/tor.html
2184 # https://github.com/spesmilo/electrum-docs/issues/129
2185 s rsync -ptog --chown bitcoin:bitcoin ~/.Xauthority /var/lib/bitcoind/.Xauthority
2186 sudo -u bitcoin DISPLAY=$DISPLAY XAUTHORITY=/var/lib/bitcoind/.Xauthority /a/opt/electrum-4.2.1-x86_64.AppImage -p socks5:localhost:9050
2187 }
2188 monero() {
2189 sudo -u bitcoin DISPLAY=$DISPLAY XAUTHORITY=/var/lib/bitcoind/.Xauthority /a/opt/monero-gui-v0.17.3.2/monero-wallet-gui
2190 }
2191
2192
2193 reset-konsole() {
2194 # we also have a file in /a/c/...konsole...
2195 local f=$HOME/.config/konsolerc
2196 setini DefaultProfile profileian.profile "Desktop Entry" $f
2197 setini Favorites profileian.profile "Favorite Profiles" $f
2198 setini ShowMenuBarByDefault false KonsoleWindow $f
2199 setini TabBarPosition Top TabBar $f
2200 }
2201
2202 reset-sakura() {
2203 while read -r k v; do
2204 # shellcheck disable=SC2154
2205 setini $k $v sakura /a/c/subdir_files/.config/sakura/sakura.conf
2206 done <<'EOF'
2207 colorset1_back rgb(33,37,39)
2208 less_questions true
2209 audible_bell No
2210 visible_bell No
2211 disable_numbered_tabswitch true
2212 scroll_lines 10000000
2213 scrollbar true
2214 EOF
2215 }
2216
2217 # make a page of links found in the files $@. redirect output
2218 linkhtml() {
2219 gr -oh 'https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)' "$@" | \
2220 rev | sort -u | rev | sed 's,.*,<a href="\0">\0</a><br\>,'
2221 }
2222
2223 reset-xscreensaver() {
2224 # except for spash, i set these by setting gui options in
2225 # xscreensaver-command -demo
2226 # then finding the corresponding option in .xscreensaver
2227 # spash, i happened to notice in .xscreensaver
2228 #
2229 # dpmsOff, monitor doesnt come back on using old free software supported nvidia card
2230 cat > /home/iank/.xscreensaver <<'EOF'
2231 mode: blank
2232 dpmsEnabled: True
2233 dpmsStandby: 0:07:00
2234 dpmsSuspend: 0:08:00
2235 dpmsOff: 0:00:00
2236 timeout: 0:05:00
2237 lock: True
2238 lockTimeout: 0:06:00
2239 splash: False
2240 EOF
2241
2242 }
2243
2244
2245 # * stuff that makes sense to be at the end
2246 if [[ "$SUDOD" ]]; then
2247 # allow failure, for example if we are sudoing into a user with diffferent/lesser permissions.
2248 cd "$SUDOD" ||:
2249 unset SUDOD
2250 elif [[ -d /a ]] && [[ $PWD == "$HOME" ]] && [[ $- == *i* ]]; then
2251 cd /a
2252 OLDPWD=
2253 fi
2254
2255
2256
2257
2258 # for mitmproxy to get a newer python.
2259 # commented until i want to use it because it
2260 # noticably slows bash startup
2261 #
2262
2263 mypyenvinit () {
2264 if [[ $EUID == 0 || ! -e ~/.pyenv/bin ]]; then
2265 echo "error: dont be root. make sure pyenv is installed"
2266 return 1
2267 fi
2268 export PATH="$HOME/.pyenv/bin:$PATH"
2269 eval "$(pyenv init -)"
2270 eval "$(pyenv virtualenv-init -)"
2271 }
2272
2273
2274 export GOPATH=$HOME/go
2275 path-add $GOPATH/bin
2276 path-add /usr/local/go/bin
2277
2278 # I have the git repo and a release. either one should work.
2279 # I have both because I was trying to solve an issue that
2280 # turned out to be unrelated.
2281 # ARDUINO_PATH=/a/opt/Arduino/build/linux/work
2282
2283 ## i should have documented this...
2284 # based on https://github.com/keyboardio/Kaleidoscope
2285 export KALEIDOSCOPE_DIR=/a/opt/Kaleidoscope
2286
2287 # They want to be added to the start, but i think
2288 # that should be avoided unless we really need it.
2289 path-add --end ~/.npm-global
2290
2291
2292 path-add --end $HOME/.cargo/bin
2293
2294 if type -P rg &>/dev/null; then
2295 # --no-messages because of annoying errors on broken symlinks
2296 # -z = search .gz etc files
2297 # -. = search dotfilesq
2298 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 $?; }
2299 #fails if not exist. ignore
2300 complete -r rg 2>/dev/null ||:
2301 else
2302 alias rg=grr
2303 fi
2304
2305
2306
2307 # taken from default changes to bashrc and bash_profile
2308 path-add --end --ifexists $HOME/.rvm/bin
2309 # also had ruby bin dir, but moved that to environment.sh
2310 # so its included in overall env
2311
2312
2313 export BASEFILE_DIR=/a/bin/fai-basefiles
2314
2315 #export ANDROID_HOME=/a/opt/android-home
2316 # https://f-droid.org/en/docs/Installing_the_Server_and_Repo_Tools/
2317 #export USE_SDK_WRAPPER=yes
2318 #PATH=$PATH:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools
2319
2320 # didnt get drush working, if I did, this seems like the
2321 # only good thing to include for it.
2322 # Include Drush completion.
2323 # if [ -f "/home/ian/.drush/drush.complete.sh" ] ; then
2324 # source /home/ian/.drush/drush.complete.sh
2325 # fi
2326
2327
2328 # best practice
2329 unset IFS
2330
2331 # https://wiki.archlinux.org/index.php/Xinitrc#Autostart_X_at_login
2332 # i added an extra condition as gentoo xorg guide says depending on
2333 # $DISPLAY is fragile.
2334 if [[ ! $DISPLAY && $XDG_VTNR == 1 ]] && shopt -q login_shell && isarch; then
2335 exec startx
2336 fi
2337
2338
2339 # ensure no bad programs appending to this file will have an affect
2340 return 0