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