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