ploopy on startup
[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
1466 net-dev-info() {
1467 e "lspci -nnk|gr -iA2 net"
1468 lspci -nnk|gr -iA2 net
1469 hr
1470 e "s lshw -C network"
1471 hr
1472 sudo lshw -C network
1473 }
1474
1475 nk() {
1476 ser stop NetworkManager
1477 ser disable NetworkManager
1478 ser stop NetworkManager-wait-online.service
1479 ser disable NetworkManager-wait-online.service
1480 ser stop dnsmasq
1481 sudo resolvconf -d NetworkManager
1482 # ser start dnsmasq
1483 sudo ifup br0
1484 }
1485 ngo() {
1486 sudo ifdown br0
1487 ser start NetworkManager
1488 sleep 4
1489 sudo nmtui-connect
1490 }
1491
1492 otp() {
1493 oathtool --totp -b "$*" | xclip -selection clipboard
1494 }
1495 j() {
1496 "$@" |& pee "xclip -r -selection clipboard"
1497 }
1498
1499
1500 pakaraoke() {
1501 # from http://askubuntu.com/questions/456021/remove-vocals-from-mp3-and-get-only-instrumentals
1502 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
1503 }
1504
1505 pfind() { #find *$1* in $PATH
1506 [[ $# != 1 ]] && { echo requires 1 argument; return 1; }
1507 local pathArray
1508 IFS=: pathArray=($PATH); unset IFS
1509 find "${pathArray[@]}" -iname "*$1*"
1510 }
1511
1512 pick-trash() {
1513 # trash-restore lists everything that has been trashed at or below CWD
1514 # This picks out files just in CWD, not subdirectories,
1515 # which also match grep $1, usually use $1 for a time string
1516 # which you get from running restore-trash once first
1517 local name x ask
1518 local nth=1
1519 # last condition is to not ask again for ones we skipped
1520 while name="$( echo | restore-trash | gr "$PWD/[^/]\+$" | gr "$1" )" \
1521 && [[ $name ]] && (( $(wc -l <<<"$name") >= nth )); do
1522 name="$(echo "$name" | head -n $nth | tail -n 1 )"
1523 read -r -p "$name [Y/n] " ask
1524 if [[ ! $ask || $ask == [Yy] ]]; then
1525 x=$( echo "$name" | gr -o "^\s*[0-9]*" )
1526 echo $x | restore-trash > /dev/null
1527 elif [[ $ask == [Nn] ]]; then
1528 nth=$((nth+1))
1529 else
1530 return
1531 fi
1532 done
1533 }
1534
1535
1536 pub() {
1537 rld /a/h/_site/ li:/var/www/iankelling.org/html
1538 }
1539
1540
1541 pumpa() {
1542 # fixes the menu bar in xmonad. this won\'t be needed when xmonad
1543 # packages catches up on some changes in future (this is written in
1544 # 4/2017)
1545 #
1546 # geekosaur: so youll want to upgrade to xmonad 0.13 or else use a
1547 # locally modified XMonad.Hooks.ManageDocks that doesnt set the
1548 # work area; turns out it\'s impossible to set correctly if you are
1549 # not a fully EWMH compliant desktop environment
1550 #
1551 # geekosaur: chrome shows one failure mode, qt/kde another, other
1552 # gtk apps a third, ... I came up with a setting that works for me
1553 # locally but apparently doesnt work for others, so we joined the
1554 # other tiling window managers in giving up on setting it at all
1555 #
1556 xprop -root -remove _NET_WORKAREA
1557 command pumpa & r
1558 }
1559
1560 # reviewboard, used at my old job
1561 #rbpipe() { rbt post -o --diff-filename=- "$@"; }
1562 #rbp() { rbt post -o "$@"; }
1563
1564 rebr() {
1565 sudo ifdown br0
1566 sudo ifup br0
1567 }
1568
1569
1570 r2e() { command r2e -d /p/c/rss2email.json -c /p/c/rss2email.cfg "$@"; }
1571 # only run on MAIL_HOST. simpler to keep this on one system.
1572 r2eadd() { # usage: name url
1573 # initial setup of rss2email:
1574 # r2e new r2e@iankelling.org
1575 # that initializes files, and sets default email.
1576 # symlink to the config doesnt work, so I copied it to /p/c
1577 # and then use cli option to specify explicit path.
1578 # Only option changed from default config is to set
1579 # force-from = True
1580 #
1581 # or else for a few feeds, the from address is set by the feed, and
1582 # if I fail delivery, then I send a bounce message to that from
1583 # address, which makes me be a spammer.
1584
1585 r2e add $1 "$2" $1@r2e.iankelling.org
1586 # get up to date and dont send old entries now:
1587 r2e run --no-send $1
1588 }
1589
1590 rspicy() { # usage: HOST DOMAIN
1591 # connect to spice vm remote host. use vspicy for local host
1592 local port
1593 # shellcheck disable=SC2087
1594 port=$(ssh $1<<EOF
1595 sudo virsh dumpxml $2|grep "<graphics.*type='spice'" | \
1596 sed -rn "s/.*port='([0-9]+).*/\1/p"
1597 EOF
1598 )
1599 if [[ $port ]]; then
1600 spicy -h $1 -p $port
1601 else
1602 echo "error: no port found. check that the domain is running."
1603 fi
1604 }
1605
1606
1607 scssl() {
1608 # s gem install scss-lint
1609 pushd /a/opt/thoughtbot-guides
1610 git pull --stat
1611 popd
1612 scss-lint -c /a/opt/thoughtbot-guides/style/sass/.scss-lint.yml "$@"
1613 }
1614
1615 skbrc() {
1616 sk -e 2120,245 /b/ds/brc /b/ds/brc2
1617 }
1618
1619 skaraoke() {
1620 local tmp out
1621 out=${2:-${1%.*}.sh}
1622 tmp=$(mktemp -d)
1623 script -t -c "mpv --no-config --no-resume-playback --no-terminal --no-audio-display '$1'" $tmp/typescript 2>$tmp/timing
1624 # todo, the current sleep seems pretty good, but it
1625 # would be nice to have an empirical measurement, or
1626 # some better wait to sync up.
1627 #
1628 # note: --loop-file=no prevents it from hanging if you have that
1629 # set to inf the mpv config.
1630 # --loop=no prevents it from exit code 3 due to stdin if you
1631 # had it set to inf in mpv config.
1632 #
1633 # args go to mpv, for example --volume=80, 50%
1634 cat >$out <<EOFOUTER
1635 #!/bin/bash
1636 trap "trap - TERM && kill 0" INT TERM ERR; set -e
1637 ( sleep .2; scriptreplay <( cat <<'EOF'
1638 $(cat $tmp/timing)
1639 EOF
1640 ) <( cat <<'EOF'
1641 $(cat $tmp/typescript)
1642 EOF
1643 ))&
1644 base64 -d - <<'EOF'| mpv --loop=no --loop-file=no --no-terminal --no-audio-display "\$@" -
1645 $(base64 "$1")
1646 EOF
1647 kill 0
1648 EOFOUTER
1649 rm -r $tmp
1650 chmod +x $out
1651 }
1652
1653 smeld() { # ssh meld usage host1 host2 file
1654 meld <(ssh $1 cat $3) <(ssh $2 cat $3)
1655 }
1656
1657 spd() {
1658 PATH=/usr/local/spdhackfix:$PATH command spd "$@"
1659 }
1660
1661 spamf() { # spamtest on FILE
1662 local spamcpre spamdpid
1663
1664 if (( $# != 1 )); then
1665 e spamtest error: expected 1 arg, filename >&2
1666 return 1
1667 fi
1668
1669 spamdpid=$(systemctl status spamassassin| sed -n '/^ *Main PID:/s/[^0-9]//gp')
1670 spamcpre="nsenter -t $spamdpid -n -m"
1671 s $spamcpre sudo -u Debian-exim spamassassin -t --cf='score PYZOR_CHECK 0' <"$1"
1672 }
1673
1674
1675 # mail related
1676 testmail() {
1677 declare -gi _seq; _seq+=1
1678 echo "test body" | m mail -s "test mail from $HOSTNAME, $_seq" "${@:-root@localhost}"
1679 # for testing to send from an external address, you can do for example
1680 # -fian@iank.bid -aFrom:ian@iank.bid web-6fnbs@mail-tester.com
1681 # note in exim, you can retry a deferred message
1682 # s exim -M MSG_ID
1683 # MSG_ID is in /var/log/exim4/mainlog, looks like 1ccdnD-0001nh-EN
1684 }
1685
1686 # to test sieve, use below command. for fsf mail, see offlineimap-sync script
1687 # make modifications, then copy to live file, use -eW to actually modify mailbox
1688 #
1689 # Another option is to use sieve-test SCRIPT MAIL_FILE. note,
1690 # sieve-test doesnt know about envelopes, Im not sure if sieve-filter does.
1691
1692 # sieve with output filter. arg is mailbox, like INBOX.
1693 # This depends on dovecot conf, notably mail_location in /etc/dovecot/conf.d/10-mail.conf
1694
1695 # always run this first, edit the test files, then run the following
1696 testsieve() {
1697 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
1698 }
1699 runsieve() {
1700 c ~/sieve; cp personal{test,}.sieve; cp lists{test,}.sieve; cp personalend{test,}.sieve
1701 sieve-filter -eWv ~/sieve/maintest.sieve ${1:-INBOX} delete &> /tmp/testsieve.log
1702 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
1703 }
1704
1705 # usage:
1706 # alertme SUBJECT
1707 # printf "subject\nbody\n" | alertme
1708 alertme() {
1709 if [[ -t 0 ]]; then
1710 exim -t <<EOF
1711 From: alertme@b8.nz
1712 To: alerts@iankelling.org
1713 Subject: $*
1714 EOF
1715 else
1716 read sub
1717 { cat <<EOF
1718 From: alertme@b8.nz
1719 To: alerts@iankelling.org
1720 Subject: $sub
1721
1722 EOF
1723 cat
1724 } | exim -t
1725 fi
1726 }
1727 daylertme() {
1728 if [[ -t 0 ]]; then
1729 exim -t <<EOF
1730 From: alertme@b8.nz
1731 To: daylert@iankelling.org
1732 Subject: $*
1733 EOF
1734 else
1735 read sub
1736 { cat <<EOF
1737 From: alertme@b8.nz
1738 To: daylert@iankelling.org
1739 Subject: $sub
1740
1741 EOF
1742 cat
1743 } | exim -t
1744 fi
1745 }
1746
1747 # alert when a page goes live.
1748 alert200() {
1749 local quiet url tmpdir
1750 quiet=false
1751 case $1 in
1752 # dont send a diff of the html. some html is not very readable
1753 -q) quiet=true
1754 shift
1755 ;;
1756 esac
1757 url="$1"
1758 tmpdir="$(mktemp -d)"
1759 cd $tmpdir
1760 while true; do
1761 if wget -q "$url"; then
1762 if $quiet; then
1763 echo | daylert 200
1764 else
1765 alertme $tmpdir
1766 fi
1767 fi
1768 sleep $(( 120 + RANDOM % 300 ))
1769 done
1770 }
1771
1772 # alert on changes to a webpage (just the base page that curl gets)
1773 # usage: weblert URL [SUBJECT...]
1774 weblert() {
1775 local u old new quiet
1776 quiet=false
1777 case $1 in
1778 # dont send a diff of the html. some html is not very readable
1779 -q) quiet=true
1780 shift
1781 ;;
1782 esac
1783 u="$1"
1784 shift
1785 subject="${*:-weblert}"
1786 old=$(curl -s "$u") ||:
1787 while true; do
1788 new=$(curl -s "$u") ||:
1789 if [[ $old && $new ]]; then
1790 if [[ $new != "$old" ]]; then
1791 if $quiet; then
1792 echo | daylertme "$subject"
1793 else
1794 diff <(printf "%s\n" "$old") <(printf "%s\n" "$new") | daylertme "$subject" ||:
1795 fi
1796 fi
1797 old="$new"
1798 fi
1799 sleep $(( 60 + RANDOM % 120 ))
1800 done
1801 }
1802
1803 torshell() {
1804 # per man torsocks
1805 source `type -p torsocks` on
1806 }
1807
1808 eless2() {
1809 less /var/log/exim4/mymain
1810 }
1811
1812
1813 # mail related
1814 testexim() {
1815 # testmail above calls sendmail, which is a link to exim/postfix.
1816 # its docs dont say a way of adding an argument
1817 # to sendmail to turn on debug output. We could make a wrapper, but
1818 # that is a pain. Exim debug args are documented here:
1819 # http://www.exim.org/exim-html-current/doc/html/spec_html/ch-the_exim_command_line.html
1820 #
1821 # http://www.exim.org/exim-html-current/doc/html/spec_html/ch-building_and_installing_exim.html
1822 # note, for exim daemon, you can turn on debug options by
1823 # adding -d, etc to COMMONOPTIONS in
1824 # /etc/default/exim4
1825 #
1826 # to specify recipients other than those in to, cc, bcc, you can use the cli args, eg:
1827 # exim -t 'test@zroe.org, t2@zroe.org' <<'EOF'
1828 #
1829 # -t = get recipient from header
1830 exim -d -t <<EOF
1831 From: root@$(hostname -f)
1832 To: root@$(hostname -f)
1833 Subject: test2
1834
1835 This is a test message.
1836 EOF
1837 }
1838
1839 # test bounce exim
1840 testbexim() {
1841 to=$1
1842 exim -d -f '<>' $to <<EOF
1843 From: Mail Delivery System <Mailer-Daemon@gnu.org>
1844 To: $to
1845 Subject: Mail delivery failed: returning message to sender
1846
1847 This message was created automatically by mail delivery software.
1848 EOF
1849
1850 }
1851
1852
1853 # toggle keyboard
1854 tk() {
1855 # based on
1856 # https://askubuntu.com/questions/160945/is-there-a-way-to-disable-a-laptops-internal-keyboard
1857 id=$(xinput --list --id-only 'AT Translated Set 2 keyboard')
1858 if xinput list | grep -F '∼ AT Translated Set 2 keyboard' &>/dev/null; then
1859 echo enabling keyboard
1860 # find the first slave keyboard number, they are all the same in my output.
1861 # if they werent, worst case we would need to save the slave number somewhere
1862 # when it got disabled.
1863 slave=$(xinput list | sed -n 's/.*slave \+keyboard (\([0-9]*\)).*/\1/p' | head -n1)
1864 xinput reattach $id $slave
1865 else
1866 xinput float $id
1867 fi
1868 }
1869
1870 tm() {
1871 # timer in minutes
1872 # --no-config
1873 (sleep $(calc "$* * 60") && mpv --no-config --volume 50 /a/bin/data/alarm.mp3) > /dev/null 2>&1 &
1874 }
1875
1876 trg() { transmission-remote-gtk & r; }
1877 trc() {
1878 # example, set global upload limit to 100 kilobytes:
1879 # trc -u 100
1880 TR_AUTH=":$(jq -r .profiles[0].password ~/.config/transmission-remote-gtk/config.json)" transmission-remote transmission.lan -ne "$@"
1881 }
1882
1883 trysleep() {
1884 retries="$1"
1885 sleepsecs="$2"
1886 shift 2
1887 for (( i=0; i < retries - 1; i++ )); do
1888 if "$@"; then
1889 return 0
1890 fi
1891 sleep $sleepsecs
1892 done
1893 "$@"
1894 }
1895
1896
1897 tu() {
1898 local s
1899 if [[ -e $1 && ! -w $1 || ! -w $(dirname "$1") ]]; then
1900 s=s;
1901 fi
1902 # full path for using in some initial setup steps
1903 $s /a/exe/teeu "$@"
1904 }
1905
1906 enn() {
1907 local ecmd pid
1908
1909 ecmd="/usr/sbin/exim4 -C /etc/exim4/my.conf"
1910 if ip a show veth1-mail &>/dev/null; then
1911 s $ecmd "$@"
1912 return
1913 fi
1914 pid=$(pgrep -f "/usr/sbin/exim4 -bd -q30m -C /etc/exim4/my.conf"|h1)
1915 m s nsenter -t $pid -n -m $ecmd "$@"
1916 }
1917
1918 # get pid of systemd service
1919 servicepid() {
1920 local pid unit dir
1921 unit="$1"
1922 pid=$(systemctl show --property MainPID --value "$unit")
1923 case $pid in
1924 [1-9]*) : ;;
1925 *)
1926
1927 dir=/sys/fs/cgroup/system.slice
1928 if [[ ! -d $dir ]]; then
1929 # t10 and older directory.
1930 dir=/sys/fs/cgroup/systemd/system.slice
1931 fi
1932
1933 # 0 or empty. This file includes the MainPid, so I expect we
1934 # could just get this in the first place, but i don't know if that
1935 # is always the case.
1936 pid=$(head -n1 $dir/${unit%.service}.service/cgroup.procs)
1937 ;;
1938 esac
1939 if [[ $pid ]]; then
1940 printf "%s\n" "$pid"
1941 else
1942 return 1
1943 fi
1944 }
1945
1946 sdnbash() { # systemd namespace bash
1947 local unit pid
1948 if (( $# != 1 )); then
1949 echo $0: error wrong number of args >&2
1950 return 1
1951 fi
1952 unit=$1
1953 pid=$(servicepid $unit)
1954 m sudo nsenter -t $pid -n -m sudo -u $USER -i bash
1955 }
1956
1957 sdnbashroot() { # systemd namespace bash
1958 local unit pid
1959 if (( $# != 1 )); then
1960 echo $0: error wrong number of args >&2
1961 return 1
1962 fi
1963 unit=$1
1964 pid=$(servicepid $unit)
1965 m sudo nsenter -t $pid -n -m bash
1966 }
1967
1968
1969 sdncmd() { # systemd namespace cmd
1970 local unit pid
1971 if (( $# <= 2 )); then
1972 echo $0: error wrong number of args >&2
1973 return 1
1974 fi
1975 unit=$1
1976 shift
1977 pid=$(servicepid $unit)
1978 m sudo nsenter -t $pid -n -m sudo -u $USER -i "$@"
1979 }
1980
1981
1982 mailnnbash() {
1983 sdnbash mailnn
1984 }
1985
1986 # we use wireguard now, use mailnnbash.
1987 # mailvpnbash() {
1988 # m sudo nsenter -t $(pgrep -f "/usr/sbin/openvpn .* --config /etc/openvpn/.*mail.conf") -n -m sudo -u $USER -i bash
1989 # }
1990
1991 eximbash() {
1992 local pid
1993 pid=$(pgrep -f "/usr/sbin/exim4 -bd -q30m -C /etc/exim4/my.conf"|h1)
1994 if [[ ! $pid ]]; then
1995 echo "eximbash: failed to find exim pid. systemctl -n 30 status exim4:"
1996 systemctl status exim4
1997 fi
1998 m sudo nsenter -t $pid -n -m
1999 }
2000 spamnn() {
2001 local spamdpid
2002 spamdpid=$(systemctl show --property MainPID --value spamassassin)
2003 m sudo nsenter -t $spamdpid -n -m sudo -u Debian-exim spamassassin "$@"
2004 }
2005 unboundbash() {
2006 m sudo nsenter -t $(systemctl status unbound| sed -n '/^ *Main PID:/s/[^0-9]//gp') -n -m sudo -u $USER -i bash
2007 }
2008
2009 nmtc() {
2010 s nmtui-connect "$@"
2011 }
2012
2013 mailnncheck() {
2014 local unit pid ns mailnn
2015 # mailvpn would belong on the list if using openvpn
2016 for unit in mailnn unbound dovecot spamassassin exim4 radicale; do
2017 pid=$(servicepid $unit)
2018 echo debug: unit=$unit pid=$pid
2019 if [[ ! $pid ]]; then
2020 echo failed to find pid for unit=$unit
2021 continue
2022 fi
2023 if ! ns=$(s readlink /proc/$pid/ns/net); then
2024 echo failed to find ns for unit=$unit pid=$pid
2025 continue
2026 fi
2027 if [[ $mailnn ]]; then
2028 if [[ $ns != "$mailnn" ]]; then
2029 echo "$unit ns $ns != $mailnn"
2030 fi
2031 else
2032 mailnn=$ns
2033 fi
2034 done
2035
2036 }
2037
2038
2039 vpncmd() {
2040 m sudo -E env "PATH=$PATH" nsenter -t $(pgrep -f "/usr/sbin/openvpn .* --config /etc/openvpn/.*client.conf") -n "$@"
2041 }
2042
2043 vpni() {
2044 vpncmd sudo -u iank env "PATH=$PATH" "$@"
2045 }
2046 vpnbash() {
2047 vpncmd bash
2048 }
2049
2050
2051 vpn() {
2052 if [[ -e /lib/systemd/system/openvpn-client@.service ]]; then
2053 local vpn_service=openvpn-client
2054 else
2055 local vpn_service=openvpn
2056 fi
2057
2058 [[ $1 ]] || { echo need arg; return 1; }
2059 journalctl --unit=$vpn_service@$1 -f -n0 &
2060 # sometimes the journal doesnt open until after the vpn output
2061 # has happened. hoping this fixes that.
2062 sleep 1
2063 sudo systemctl start $vpn_service@$1
2064 # sometimes the ask-password agent does not work and needs a delay.
2065 sleep .5
2066 # https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=779240
2067 # noticed around 8-2017 after update from around stretch release
2068 # on debian testing, even though the bug is much older.
2069 sudo systemd-tty-ask-password-agent
2070 }
2071
2072 fixu() {
2073 local stats
2074 ls -lad /run/user/1000
2075 stats=$(stat -c%a-%g-%u /run/user/1000)
2076 if [[ $stats != 700-1000-1000 ]]; then
2077 m s chmod 700 /run/user/1000; m s chown iank.iank /run/user/1000
2078 fi
2079 }
2080
2081 # systemctl is-enabled / status / cat says nothing, instead theres
2082 # some obscure symlink. paths copied from man systemd.unit.
2083 # possibly also usefull, but incomplete, doesnt show units not loaded in memory:
2084 # seru list-dependencies --reverse --all UNIT
2085 sysd-deps() {
2086 local f
2087 local -a dirs search
2088 ngset
2089
2090 case $1 in
2091 u)
2092 search=(
2093 ~/.config/systemd/user.control/*
2094 $XDG_RUNTIME_DIR/systemd/user.control/*
2095 $XDG_RUNTIME_DIR/systemd/transient/*
2096 $XDG_RUNTIME_DIR/systemd/generator.early/*
2097 ~/.config/systemd/user/*
2098 /etc/systemd/user/*
2099 $XDG_RUNTIME_DIR/systemd/user/*
2100 /run/systemd/user/*
2101 $XDG_RUNTIME_DIR/systemd/generator/*
2102 ~/.local/share/systemd/user/*
2103 /usr/lib/systemd/user/*
2104 $XDG_RUNTIME_DIR/systemd/generator.late/*
2105 )
2106 ;;
2107 *)
2108 search=(
2109 /etc/systemd/system.control/*
2110 /run/systemd/system.control/*
2111 /run/systemd/transient/*
2112 /run/systemd/generator.early/*
2113 /etc/systemd/system/*
2114 /etc/systemd/systemd.attached/*
2115 /run/systemd/system/*
2116 /run/systemd/systemd.attached/*
2117 /run/systemd/generator/*
2118 /lib/systemd/system/*
2119 /run/systemd/generator.late/*
2120 )
2121 ;;
2122 esac
2123 for f in "${search[@]}"; do
2124 [[ -d $f ]] || continue
2125 case $f in
2126 *.requires|*.wants)
2127 dirs+=("$f")
2128 ;;
2129 esac
2130 done
2131 # dirs is just so we write out the directory names, ls does it when there is 2 or more dirs.
2132 case ${#dirs[@]} in
2133 1)
2134 echo "${dirs[0]}:"
2135 ll "${dirs[@]}"
2136 ;;
2137 0) : ;;
2138 *)
2139 ll "${dirs[@]}"
2140 ;;
2141 esac
2142 ngreset
2143 }
2144
2145 fixvpndns() {
2146 local link istls
2147 read _ link _ istls < <(resolvectl dnsovertls tunfsf)
2148 case $istls in
2149 yes|no) : ;;
2150 *) echo fixvpndns error: unexpected istls value: $istls >&2; return 1 ;;
2151 esac
2152 s busctl call org.freedesktop.resolve1 /org/freedesktop/resolve1 org.freedesktop.resolve1.Manager SetLinkDNSOverTLS is $link no
2153 }
2154
2155 vpnoff() {
2156 [[ $1 ]] || { echo need arg; return 1; }
2157 if [[ -e /lib/systemd/system/openvpn-client@.service ]]; then
2158 local vpn_service=openvpn-client
2159 else
2160 local vpn_service=openvpn
2161 fi
2162 sudo systemctl stop $vpn_service@$1
2163 }
2164 vpnoffc() { # vpn off client
2165 ser stop openvpn-client-tr@client
2166 }
2167 vpnc() {
2168 ser start openvpn-client-tr@client
2169 }
2170
2171
2172 vspicy() { # usage: VIRSH_DOMAIN
2173 # connect to vms made with virt-install
2174 spicy -p $(sudo virsh dumpxml "$1"|grep "<graphics.*type='spice'"|\
2175 sed -r "s/.*port='([0-9]+).*/\1/")
2176 }
2177
2178 wian() {
2179 cat-new-files /m/4e/INBOX/new
2180 }
2181
2182 wtr() { curl wttr.in/boston; }
2183
2184 xevkb() { xev -event keyboard; }
2185
2186 # * misc stuff
2187
2188 vrun() {
2189 printf "running: %s\n" "$*"
2190 "$@"
2191 }
2192
2193 f=/a/f/ansible-configs/files/common/etc/fsf-workstation-bashrc.sh
2194 if [[ -e $f ]]; then
2195 # shellcheck disable=SC1090
2196 source $f
2197 fi
2198
2199 electrum() {
2200 # https://electrum.readthedocs.io/en/latest/tor.html
2201 # https://github.com/spesmilo/electrum-docs/issues/129
2202 s rsync -ptog --chown bitcoin:bitcoin ~/.Xauthority /var/lib/bitcoind/.Xauthority
2203 sudo -u bitcoin DISPLAY=$DISPLAY XAUTHORITY=/var/lib/bitcoind/.Xauthority /a/opt/electrum-4.2.1-x86_64.AppImage -p socks5:localhost:9050
2204 }
2205 monero() {
2206 sudo -u bitcoin DISPLAY=$DISPLAY XAUTHORITY=/var/lib/bitcoind/.Xauthority /a/opt/monero-gui-v0.17.3.2/monero-wallet-gui
2207 }
2208
2209
2210 reset-konsole() {
2211 # we also have a file in /a/c/...konsole...
2212 local f=$HOME/.config/konsolerc
2213 setini DefaultProfile profileian.profile "Desktop Entry" $f
2214 setini Favorites profileian.profile "Favorite Profiles" $f
2215 setini ShowMenuBarByDefault false KonsoleWindow $f
2216 setini TabBarPosition Top TabBar $f
2217 }
2218
2219 reset-sakura() {
2220 while read -r k v; do
2221 # shellcheck disable=SC2154
2222 setini $k $v sakura /a/c/subdir_files/.config/sakura/sakura.conf
2223 done <<'EOF'
2224 colorset1_back rgb(33,37,39)
2225 less_questions true
2226 audible_bell No
2227 visible_bell No
2228 disable_numbered_tabswitch true
2229 scroll_lines 10000000
2230 scrollbar true
2231 EOF
2232 }
2233
2234 # make a page of links found in the files $@. redirect output
2235 linkhtml() {
2236 gr -oh 'https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)' "$@" | \
2237 rev | sort -u | rev | sed 's,.*,<a href="\0">\0</a><br\>,'
2238 }
2239
2240 reset-xscreensaver() {
2241 # except for spash, i set these by setting gui options in
2242 # xscreensaver-command -demo
2243 # then finding the corresponding option in .xscreensaver
2244 # spash, i happened to notice in .xscreensaver
2245 #
2246 # dpmsOff, monitor doesnt come back on using old free software supported nvidia card
2247 cat > /home/iank/.xscreensaver <<'EOF'
2248 mode: blank
2249 dpmsEnabled: True
2250 dpmsStandby: 0:07:00
2251 dpmsSuspend: 0:08:00
2252 dpmsOff: 0:00:00
2253 timeout: 0:05:00
2254 lock: True
2255 lockTimeout: 0:06:00
2256 splash: False
2257 EOF
2258
2259 }
2260
2261
2262 # * stuff that makes sense to be at the end
2263 if [[ "$SUDOD" ]]; then
2264 # allow failure, for example if we are sudoing into a user with diffferent/lesser permissions.
2265 cd "$SUDOD" ||:
2266 unset SUDOD
2267 elif [[ -d /a ]] && [[ $PWD == "$HOME" ]] && [[ $- == *i* ]]; then
2268 cd /a
2269 OLDPWD=
2270 fi
2271
2272
2273
2274
2275 # for mitmproxy to get a newer python.
2276 # commented until i want to use it because it
2277 # noticably slows bash startup
2278 #
2279
2280 mypyenvinit () {
2281 if [[ $EUID == 0 || ! -e ~/.pyenv/bin ]]; then
2282 echo "error: dont be root. make sure pyenv is installed"
2283 return 1
2284 fi
2285 export PATH="$HOME/.pyenv/bin:$PATH"
2286 eval "$(pyenv init -)"
2287 eval "$(pyenv virtualenv-init -)"
2288 }
2289
2290
2291 export GOPATH=$HOME/go
2292 path-add $GOPATH/bin
2293 path-add /usr/local/go/bin
2294
2295 # I have the git repo and a release. either one should work.
2296 # I have both because I was trying to solve an issue that
2297 # turned out to be unrelated.
2298 # ARDUINO_PATH=/a/opt/Arduino/build/linux/work
2299
2300 ## i should have documented this...
2301 # based on https://github.com/keyboardio/Kaleidoscope
2302 export KALEIDOSCOPE_DIR=/a/opt/Kaleidoscope
2303
2304 # They want to be added to the start, but i think
2305 # that should be avoided unless we really need it.
2306 path-add --end ~/.npm-global
2307
2308
2309 path-add --end $HOME/.cargo/bin
2310
2311 if type -P rg &>/dev/null; then
2312 # --no-messages because of annoying errors on broken symlinks
2313 # -z = search .gz etc files
2314 # -. = search dotfilesq
2315 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 $?; }
2316 #fails if not exist. ignore
2317 complete -r rg 2>/dev/null ||:
2318 else
2319 alias rg=grr
2320 fi
2321
2322
2323
2324 # taken from default changes to bashrc and bash_profile
2325 path-add --end --ifexists $HOME/.rvm/bin
2326 # also had ruby bin dir, but moved that to environment.sh
2327 # so its included in overall env
2328
2329
2330 export BASEFILE_DIR=/a/bin/fai-basefiles
2331
2332 #export ANDROID_HOME=/a/opt/android-home
2333 # https://f-droid.org/en/docs/Installing_the_Server_and_Repo_Tools/
2334 #export USE_SDK_WRAPPER=yes
2335 #PATH=$PATH:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools
2336
2337 # didnt get drush working, if I did, this seems like the
2338 # only good thing to include for it.
2339 # Include Drush completion.
2340 # if [ -f "/home/ian/.drush/drush.complete.sh" ] ; then
2341 # source /home/ian/.drush/drush.complete.sh
2342 # fi
2343
2344
2345 # best practice
2346 unset IFS
2347
2348 # https://wiki.archlinux.org/index.php/Xinitrc#Autostart_X_at_login
2349 # i added an extra condition as gentoo xorg guide says depending on
2350 # $DISPLAY is fragile.
2351 if [[ ! $DISPLAY && $XDG_VTNR == 1 ]] && shopt -q login_shell && isarch; then
2352 exec startx
2353 fi
2354
2355
2356 # ensure no bad programs appending to this file will have an affect
2357 return 0