Mainly add external monitoring of mail server
[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 HISTFILE=$HOME/.bh
10
11 source /a/bin/distro-setup/path-add-function
12 path-add /a/exe
13 # add this with absolute paths as needed for better security
14 #path-add --end /path/to/node_modules/.bin
15
16 # pip3 --user things go here:
17 path-add --end ~/.local/bin
18 path-add --ifexists --end /a/work/libremanage
19 path-add --ifexists --end /a/opt/adt-bundle*/tools /a/opt/adt-bundle*/platform-tools
20 path-add --ifexists --end /a/opt/scancode-toolkit-3.0.2
21
22 export WCDHOME=/a
23
24
25 # * include files
26
27 # generated instead of dynamic for the benefit of shellcheck
28 #for x in /a/bin/distro-functions/src/* /a/bin/!(githtml)/*-function?(s); do echo source $x ; done
29 source /a/bin/distro-functions/src/identify-distros
30 source /a/bin/distro-functions/src/package-manager-abstractions
31 source /a/bin/log-quiet/logq-function
32 source /a/bin/small-misc-bash/psg-function
33 # for x in /a/bin/bash_unpublished/source-!(.#*); do echo source $x; done
34 source /a/bin/bash_unpublished/source-semi-priv
35 source /a/bin/bash_unpublished/source-state
36
37 source /a/bin/log-quiet/logq-function
38
39
40
41 # * functions
42
43
44
45 # todo, update this
46 complete -F _longopt la lower low rlt rld rl lld ts ll dircp ex fcp fct fpst gr
47
48
49 anki() {
50 if which anki &>/dev/null; then
51 command anki
52 else
53 schroot -c anki -- anki
54 fi
55 }
56
57 acat() {
58 shopt -s nullglob
59 hrcat /m/md/alerts/new/* /m/md/alerts/cur/*
60 shopt -u nullglob
61 }
62 aclear() {
63 shopt -s nullglob
64 files=(/m/md/alerts/new/* /m/md/alerts/cur/*)
65 if (( ${#files[@]} )); then
66 rm -f ${files[@]}
67 fi
68 shopt -u nullglob
69 system-status _
70 }
71
72 ap() {
73 # pushd in case current directory has an ansible.cfg file
74 pushd /a/xans >/dev/null
75 ansible-playbook -v -l ${1:- $(hostname -f)} site.yml
76 popd >/dev/null
77 }
78 aw() {
79 pushd /a/work/ansible-configs >/dev/null
80 time ansible-playbook -v -i inventory adhoc.yml "$@"
81 popd >/dev/null
82 }
83 ad() {
84 pushd /a/bin/distro-setup/a >/dev/null
85 ansible-playbook site.yml
86 popd >/dev/null
87 }
88
89 astudio() {
90 # googling android emulator libGL error: failed to load driver: r600
91 # lead to http://stackoverflow.com/a/36625175/14456
92 export ANDROID_EMULATOR_USE_SYSTEM_LIBS=1
93 /a/opt/android-studio/bin/studio.sh "$@" &r;
94 }
95
96 bindpush() {
97 lipush || return 1
98 for h in li l2; do
99 sl $h <<'EOF' || return 1
100 set -e
101 conflink
102 f=/var/lib/bind/db.b8.nz
103 ser stop bind9
104 s rm -fv $f.jnl
105 s install -m 644 -o bind -g bind /p/c/machine_specific/linode/bind-initial/db.b8.nz $f
106 ser restart bind9
107 EOF
108 done
109 }
110
111 bbk() { # btrbk wrapper
112 c /
113 local active=true
114 systemctl is-active btrbk.timer || active=false
115 if $active; then
116 ser disable btrbk.timer
117 fi
118 if systemctl is-active btrbk.service; then
119 $active && ser enable btrbk.timer
120 echo "cron btrbk is already running"
121 return 1
122 fi
123 # run latest
124 install-my-scripts
125 btrbk-run "$@" |& pee cat "systemd-cat -t btrbk-run"
126 if $active; then
127 ser enable btrbk.timer
128 fi
129 }
130
131 bfg() { java -jar /a/opt/bfg-1.12.14.jar "$@"; }
132
133 bigclock() {
134 xclock -digital -update 1 -face 'arial black-80:bold'
135 }
136
137 bpull() {
138 [[ $1 ]] || return 1
139 c /
140 # run latest
141 install-my-scripts
142 switch-mail-host pull $1 |& pee cat "systemd-cat -t switch-mail-host"
143 }
144 bpush() {
145 [[ $1 ]] || return 1
146 c /
147 # run latest
148 install-my-scripts
149 switch-mail-host push $1 |& pee cat "systemd-cat -t switch-mail-host"
150 }
151 lipush() {
152 # note, i had --delete-excluded, but that deletes all files in --exclude-from on
153 # the remote site, which doesn't make sense, so not sure why i had it.
154 local p a
155 p=(/a/bin /a/exe /a/h /a/c /p/c/machine_specific/linode{,.hosts} /a/opt/{emacs,emacs-debianstable,mu})
156 a="-ahviSAXPH --specials --devices --delete --relative --exclude-from=/p/c/li-rsync-excludes"
157 ret=0
158 m rsync "$@" $a ${p[@]} /p/c/machine_specific/l2 root@l2.b8.nz:/ || ret=$?
159 m rsync "$@" $a ${p[@]} /p/c/machine_specific/li root@li.b8.nz:/ || ret=$?
160 m rsync "$@" -ahviSAXPH root@iankelling.org:/a/h/proposed-comments/ /a/h/proposed-comments || ret=$?
161 return $ret
162 }
163 lipushnoe() { # noe = noemacs. for running faster.
164 rsync "$@" --delete-excluded -ahviSAXPH --specials --devices --delete --relative \
165 --exclude-from=/p/c/li-rsync-excludes /a/bin /a/exe /a/h /a/c /p/c/machine_specific/li root@li:/
166 }
167
168 #### begin bitcoin related things
169 btc() {
170 local f=/etc/bitcoin/bitcoin.conf
171 # importprivkey will timeout if using the default of 15 mins.
172 # upped it to 1 hour.
173 bitcoin-cli -rpcclienttimeout=60000 -$(s grep rpcuser= $f) -$(s grep rpcpassword= $f) "$@"
174 }
175 btcusd() { # $1 btc in usd
176 local price
177 price="$(curl -s https://api.coinbase.com/v2/prices/BTC-USD/spot | jq -r .data.amount)"
178 printf "$%s\n" "$price"
179 if [[ $1 ]]; then
180 printf "$%.2f\n" "$(echo "scale=4; $price * $1"| bc -l)"
181 fi
182 }
183 usdbtc() { # $1 usd in btc
184 local price
185 price="$(curl -s https://api.coinbase.com/v2/prices/BTC-USD/spot | jq -r .data.amount)"
186 printf "$%s\n" "$price"
187 if [[ $1 ]]; then
188 # 100 mil satoshi / btc. 8 digits after the 1.
189 printf "%.8f btc\n" "$(echo "scale=10; $1 / $price "| bc -l)"
190 fi
191 }
192 satoshi() { # $1 satoshi in usd
193 local price
194 price="$(curl -s https://api.coinbase.com/v2/prices/BTC-USD/spot | jq -r .data.amount)"
195 price=$(echo "scale=10; $price * 0.00000001"| bc -l)
196 printf "$%f\n" "$price"
197 if [[ $1 ]]; then
198 printf "$%.2f\n" "$(echo "scale=10; $price * $1"| bc -l)"
199 fi
200 }
201 #### end bitcoin related things
202
203
204
205 cbfstool () { /a/opt/coreboot/build/cbfstool "$@"; }
206
207
208 cgpl()
209 {
210 if (($#)); then
211 cp /a/bin/data/COPYING "$@"
212 else
213 cp /a/bin/data/COPYING .
214 fi
215 }
216
217 capache()
218 {
219 if (($#)); then
220 cp /a/bin/data/LICENSE "$@"
221 else
222 cp /a/bin/data/LICENSE .
223 fi
224 }
225
226 chrome() {
227 if type -p chromium &>/dev/null; then
228 cmd=chromium
229 else
230 cd
231 cmd="schroot -c stretch chromium"
232 CHROMIUM_FLAGS='--enable-remote-extensions' $cmd &r
233 fi
234 }
235
236
237 # do all tee.
238 # pipe to this, or just type like a shell
239 dat() {
240 tee >(ssh frodo.b8.nz bash -l) >(ssh x2 bash -l) >(ssh tp.b8.nz bash -l) >(ssh kw bash -l) >(ssh tp.b8.nz bash -l)
241 }
242 da() { # do all
243 local host
244 for host in x2 kw tp.b8.nz x3.b8.nz frodo.b8.nz; do
245 ssh $host "$@"
246 done
247 }
248
249
250 debian_pick_mirror () {
251 # netselect-apt finds a fast mirror.
252 # but we need to replace the mirrors ourselves,
253 # because it doesnt do that. best it can do is
254 # output a basic sources file
255 # here we get the server it found, get the main server we use
256 # then substitute all instances of one for the other in the sources file
257 # and backup original to /etc/apt/sources.list-original.
258 # this is idempotent. the only way to identify debian sources is to
259 # note the original server, so we put it in a comment so we can
260 # identify it later.
261 local file
262 file=$(mktemp -d)/f # safe way to get file name without creating one
263 sudo netselect-apt -o "$file" || return 1
264 url=$(grep ^\\w $file | head -n1 | awk '{print $2}')
265 sudo cp -f /etc/apt/sources.list /etc/apt/sources.list-original
266 sudo sed -ri "/http.us.debian.org/ s@( *[^ #]+ +)[^ ]+([^#]+).*@\1$url\2# http.us.debian.org@" /etc/apt/sources.list
267 sudo apt-get update
268 }
269 digme() {
270 digdiff @ns{1,2}.iankelling.org "$@"
271 }
272
273
274 dup() {
275 local ran_d
276 ran_d=false
277 system-status _
278 case $PS1 in
279 *DISTRO-BEGIN!*|*DISTRO!*)
280 pushd /
281 /b/ds/distro-begin || return $?
282 popd
283 ran_d=true
284 ;;&
285 *DISTRO-END!*|*DISTRO!*)
286 pushd
287 /b/ds/distro-end || return $?
288 popd
289 ran_d=true
290 ;;&
291 *CONFLINK*)
292 if ! $ran_d; then
293 conflink
294 fi
295 ;;
296 esac
297 system-status _
298 }
299
300 envload() { # load environment from a previous: export > file
301 local file=${1:-$HOME/.${USER}_env}
302 eval "$(export | sed 's/^declare -x/export -n/')"
303 while IFS= read -r line; do
304 # declare -x makes variables local to a function
305 eval ${line/#declare -x/export}
306 done < "$file"
307 }
308
309
310 # one that comes with distros is too old for newer devices
311 fastboot() {
312 /a/opt/android-platform-tools/fastboot "$@";
313 }
314
315 kdecd() { /usr/lib/x86_64-linux-gnu/libexec/kdeconnectd; }
316
317 # List of apps to install/update
318 # Create from existing manually installed apps by doing
319 # fdroidcl update
320 # fdroidcl search -i, then manually removing
321 # automatically installed/preinstalled apps
322
323 #
324 # # my attempt at recovering from boot loop:
325 # # in that case, boot to recovery (volume up, home button, power, let go of power after samsun logo)
326 # # then
327 # mount /dev/block/mmcblk0p12 /data
328 # cd /data
329 # find -iname '*appname*'
330 # rm -rf FOUND_DIRS
331 # usually good enough to just rm -rf /data/app/APPNAME
332 #
333 # currently broken:
334 # # causes replicant to crash
335 # org.quantumbadger.redreader
336 # org.kde.kdeconnect_tp
337
338 # not broke, but wont work without gps
339 #com.zoffcc.applications.zanavi
340 # not broke, but not using atm
341 #com.nutomic.syncthingandroid
342 # # doesn\'t work on replicant
343 #net.sourceforge.opencamera
344 #
345 fdroid_pkgs=(
346 de.marmaro.krt.ffupdater
347 me.ccrama.redditslide
348 org.fedorahosted.freeotp
349 at.bitfire.davdroid
350 com.alaskalinuxuser.justnotes
351 com.artifex.mupdf.viewer.app
352 com.danielkim.soundrecorder
353 com.fsck.k9
354 com.ghostsq.commander
355 com.ichi2.anki
356 com.jmstudios.redmoon
357 com.jmstudios.chibe
358 org.kde.kdeconnect_tp
359 com.notecryptpro
360 com.termux
361 cz.martykan.forecastie
362 de.danoeh.antennapod
363 de.blinkt.openvpn
364 de.marmaro.krt.ffupdater
365 eu.siacs.conversations
366 free.rm.skytube.oss
367 im.vector.alpha # riot
368 info.papdt.blackblub
369 me.tripsit.tripmobile
370 net.gaast.giggity
371 net.minetest.minetest
372 net.osmand.plus
373 org.isoron.uhabits
374 org.linphone
375 org.gnu.icecat
376 org.smssecure.smssecure
377 org.yaaic
378 sh.ftp.rocketninelabs.meditationassistant.opensource
379 )
380 # https://forum.xda-developers.com/android/software-hacking/wip-selinux-capable-superuser-t3216394
381 # for maru,
382 #me.phh.superuser
383
384 fdup() {
385 local -A installed updated
386 local p
387 # tried putting this in go buildscript cronjob,
388 # but it failed with undefined: os.UserCacheDir. I expect its due to
389 # an environment variable missing, but its easier just to stick it here.
390 m go get -u mvdan.cc/fdroidcl || return 1
391 m fdroidcl update
392 if fdroidcl search -u | grep ^org.fdroid.fdroid; then
393 fdroidcl install org.fdroid.fdroid
394 sleep 5
395 m fdroidcl update
396 fi
397 for p in $(fdroidcl search -i| grep -o "^\S\+"); do
398 installed[$p]=true
399 done
400 for p in $(fdroidcl search -u| grep -o "^\S\+"); do
401 updated[$p]=false
402 done
403 for p in ${fdroid_pkgs[@]}; do
404 if ! ${installed[$p]:-false}; then
405 m fdroidcl install $p
406 # sleeps are just me being paranoid since replicant has a history of crashing when certain apps are installed
407 sleep 5
408 fi
409 done
410 for p in ${!installed[@]}; do
411 if ! ${updated[$p]:-true}; then
412 m fdroidcl install $p
413 sleep 5
414 fi
415 done
416 }
417
418 firefox-default-profile() {
419 key=Default value=1 section=$1
420 file=/p/c/subdir_files/.mozilla/firefox/profiles.ini
421 sed -ri "/^ *$key/d" "$file"
422 sed -ri "/ *\[$section\]/,/^ *\[[^]]+\]/{/^\s*$key[[:space:]=]/d};/ *\[$section\]/a $key=$value" "$file"
423 }
424 fdhome() { #firefox default home profile
425 firefox-default-profile Profile0
426 }
427
428 fdwork() {
429 firefox-default-profile Profile4
430 }
431
432 ff() {
433 if type -P firefox &>/dev/null; then
434 firefox "$@"
435 else
436 iceweasel "$@"
437 fi
438 }
439
440
441
442 fn() {
443 firefox -P alt "$@" >/dev/null 2>&1
444 }
445
446
447 fsdiff () {
448 local missing=false
449 local dname="${PWD##*/}"
450 local m="/a/tmp/$dname-missing"
451 local d="/a/tmp/$dname-diff"
452 [[ -e $d ]] && rm "$d"
453 [[ -e $m ]] && rm "$m"
454 local msize=0
455 local fsfile
456 while read -r line; do
457 fsfile="$1${line#.}"
458 if [[ -e "$fsfile" ]]; then
459 md5diff "$line" "$fsfile" && tee -a "/a/tmp/$dname-diff" <<< "$fsfile $line"
460 else
461 missing=true
462 echo "$line" >> "$m"
463 msize=$((msize + 1))
464 fi
465 done < <(find . -type f )
466 if $missing; then
467 echo "$m"
468 (( msize <= 100 )) && cat $m
469 fi
470 }
471 fsdiff-test() {
472 # expected output, with different tmp dirs
473 # /tmp/tmp.HDPbwMqdC9/c/d ./c/d
474 # /a/tmp/tmp.qLDkYxBYPM-missing
475 # ./b
476 cd $(mktemp -d)
477 echo ok > a
478 echo nok > b
479 mkdir c
480 echo ok > c/d
481 local x
482 x=$(mktemp -d)
483 mkdir $x/c
484 echo different > $x/c/d
485 echo ok > $x/a
486 fsdiff $x
487 }
488 rename-test() {
489 # test whether missing files were renamed, generally for use with fsdiff
490 # $1 = fsdiff output file, $2 = directory to compare to. pwd = fsdiff dir
491 # echos non-renamed files
492 local x y found
493 unset sums
494 for x in "$2"/*; do
495 { sums+=( "$(md5sum < "$x")" ) ; } 2>/dev/null
496 done
497 while read -r line; do
498 { missing_sum=$(md5sum < "$line") ; } 2>/dev/null
499 renamed=false
500 for x in "${sums[@]}"; do
501 if [[ $missing_sum == "$x" ]]; then
502 renamed=true
503 break
504 fi
505 done
506 $renamed || echo "$line"
507 done < "$1"
508 return 0
509 }
510
511 feh() {
512 # F = fullscren, z = random, Z = auto zoom
513 command feh -FzZ "$@"
514 }
515
516
517
518 fw() {
519 firefox -P default "$@" >/dev/null 2>&1
520 }
521
522 gitian() {
523 git config user.email ian@iankelling.org
524 }
525
526 # at least in flidas, things rely on gpg being gpg1
527 gpg() {
528 command gpg2 "$@"
529 }
530
531 gse() {
532 local email=ian@iankelling.org
533 if readlink ~/.mu | grep fsf &>/dev/null; then
534 email=iank@fsf.org
535 fi
536 git send-email --notes "--envelope-sender=<$email>" \
537 --suppress-cc=self "$@"
538 }
539
540 hstatus() {
541 # do git status on published repos.
542 c /a/bin/githtml
543 for x in *; do
544 cd $(readlink -f $x)/..
545 status=$(i status -s) || pwd
546 if [[ $status ]]; then
547 hr
548 echo $x
549 printf "%s\n" "$status"
550 fi
551 cd /a/bin/githtml
552 done
553 }
554
555 idea() {
556 /a/opt/idea-IC-163.7743.44/bin/idea.sh "$@" &r
557 }
558
559 ilog() {
560 chan=${1:-#fsfsys}
561 # use * instead of -r since that does sorted order
562 ssh root@iankelling.org "cd /var/lib/znc/moddata/log/iank/freenode/$chan && hr && for x in *; do echo \$x; cat \$x; hr; done" | less +G
563 }
564
565 o() {
566 if type gvfs-open &> /dev/null ; then
567 gvfs-open "$@"
568 else
569 xdg-open "$@"
570 fi
571 # another alternative is run-mailcap
572 }
573
574 jfilter() {
575 grep -Evi -e "^(\S+\s+){4}(sudo|sshd|cron)\[\S*:" \
576 -e "^(\S+\s+){4}systemd\[\S*: (starting|started) (btrfsmaintstop|dynamicipupdate|spamd dns bug fix cronjob|rss2email)\.*$"
577 }
578 jtail() {
579 journalctl -n 10000 -f "$@" | jfilter
580 }
581 jr() { journalctl "$@" | jfilter | less ; }
582 jrf() { journalctl -n 200 -f "$@" | jfilter; }
583
584
585 kff() { # keyboardio firmware flash
586 pushd /a/bin/distro-setup/Arduino/Model01-Firmware
587 yes $'\n' | make flash
588 popd
589 }
590
591
592
593 lom() {
594 local l base
595 if [[ $1 == /* ]]; then
596 base=${1##*/}
597 if mountpoint /mnt/$base; then
598 return 0
599 fi
600 l=$(sudo losetup -f)
601 sudo losetup $l $1
602 if ! sudo cryptsetup luksOpen $l $base; then
603 sudo losetup -d $l
604 return 1
605 fi
606 sudo mkdir -p /mnt/$base
607 sudo mount /dev/mapper/$base /mnt/$base
608 sudo chown $USER:$USER /mnt/$base
609 else
610 base=$1
611 sudo umount /mnt/$base
612 l=$(sudo cryptsetup status /dev/mapper/$base|sed -rn 's/^\s*device:\s*(.*)/\1/p')
613 sudo cryptsetup luksClose /dev/mapper/$base || return 1
614 sudo losetup -d $l
615 fi
616 }
617
618
619 mbenable() {
620 local mb=$1
621 dst=/m/4e/$mb
622 src=/m/md/$mb
623 set -x
624 [[ -e $src ]] || { set +x; return 1; }
625 mv -T $src $dst || { set +x; return 1; }
626 ln -s -T $dst $src
627 /a/exe/lnf /m/.mu ~
628 mu index --maildir=/m/4e
629 set +x
630 }
631 mbdisable() {
632 local mb=$1
633 dst=/m/md/$mb
634 src=/m/4e/$mb
635 set -x
636 [[ -e $src ]] || { set +x; return 1; }
637 if [[ -L $dst ]]; then rm $dst; fi
638 mv -T $src $dst
639 set +x
640 }
641
642
643 mdt() {
644 markdown "$1" >/tmp/mdtest.html
645 firefox /tmp/mdtest.html
646 }
647
648 mo() { xset dpms force off; } # monitor off
649
650 myirc() {
651 chan=${1:-fsf-office}
652 # use * instead of -r since that does sorted order
653 ssh root@iankelling.org "cd /var/lib/znc/moddata/log/iank/freenode/#$chan; grep '\<iank.*' *"
654 }
655
656 net-dev-info() {
657 e "lspci -nnk|gr -iA2 net"
658 lspci -nnk|gr -iA2 net
659 hr
660 e "s lshw -C network"
661 hr
662 s lshw -C network
663 }
664
665 nk() {
666 ser stop NetworkManager
667 ser stop dnsmasq
668 s resolvconf -d NetworkManager
669 ser start dnsmasq
670 s ifup br0
671 }
672 ngo() {
673 s ifdown br0
674 ser start NetworkManager
675 sleep 4
676 s nmtui-connect
677 }
678
679 otp() {
680 oathtool --totp -b "$@" | xclip -selection clipboard
681 }
682
683
684 pakaraoke() {
685 # from http://askubuntu.com/questions/456021/remove-vocals-from-mp3-and-get-only-instrumentals
686 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
687 }
688
689 pfind() { #find *$1* in $PATH
690 [[ $# != 1 ]] && { echo requires 1 argument; return 1; }
691 local pathArray
692 IFS=: pathArray=($PATH); unset IFS
693 find "${pathArray[@]}" -iname "*$1*"
694 }
695
696 pick-trash() {
697 # trash-restore lists everything that has been trashed at or below CWD
698 # This picks out files just in CWD, not subdirectories,
699 # which also match grep $1, usually use $1 for a time string
700 # which you get from running restore-trash once first
701 local name x ask
702 local nth=1
703 # last condition is to not ask again for ones we skipped
704 while name="$( echo | restore-trash | gr "$PWD/[^/]\+$" | gr "$1" )" \
705 && [[ $name ]] && (( $(wc -l <<<"$name") >= nth )); do
706 name="$(echo "$name" | head -n $nth | tail -n 1 )"
707 read -r -p "$name [Y/n] " ask
708 if [[ ! $ask || $ask == [Yy] ]]; then
709 x=$( echo "$name" | gr -o "^\s*[0-9]*" )
710 echo $x | restore-trash > /dev/null
711 elif [[ $ask == [Nn] ]]; then
712 nth=$((nth+1))
713 else
714 return
715 fi
716 done
717 }
718
719
720 pub() {
721 rld /a/h/_site/ li:/var/www/iankelling.org/html
722 }
723
724
725 pumpa() {
726 # fixes the menu bar in xmonad. this won\'t be needed when xmonad
727 # packages catches up on some changes in future (this is written in
728 # 4/2017)
729 #
730 # geekosaur: so youll want to upgrade to xmonad 0.13 or else use a
731 # locally modified XMonad.Hooks.ManageDocks that doesnt set the
732 # work area; turns out it\'s impossible to set correctly if you are
733 # not a fully EWMH compliant desktop environment
734 #
735 # geekosaur: chrome shows one failure mode, qt/kde another, other
736 # gtk apps a third, ... I came up with a setting that works for me
737 # locally but apparently doesnt work for others, so we joined the
738 # other tiling window managers in giving up on setting it at all
739 #
740 xprop -root -remove _NET_WORKAREA
741 command pumpa &r
742 }
743
744 # reviewboard, used at my old job
745 #rbpipe() { rbt post -o --diff-filename=- "$@"; }
746 #rbp() { rbt post -o "$@"; }
747
748 rebr() {
749 s ifdown br0
750 s ifup br0
751 }
752
753 resolvcat() {
754 local f
755 m s nscd -i hosts
756 f=/etc/resolv.conf
757 echo $f:; ccat $f
758 hr; m ser status dnsmasq | cat
759 hr; s ss -lpn 'sport = 53'
760 #hr; echo dnsmasq is $(systemctl is-active dnsmasq)
761 f=/var/run/dnsmasq/resolv.conf
762 hr; echo $f:; ccat $f
763 hr; m grr '^ *servers-file *=' /etc/dnsmasq.conf /etc/dnsmasq.d
764 f=/etc/dnsmasq-servers.conf
765 hr; echo $f:; ccat $f
766 }
767 rcat() {
768 resolvcat | less
769 }
770
771 # only run on MAIL_HOST. simpler to keep this on one system.
772 r2eadd() { # usage: name url
773 # initial setup of rss2email:
774 # r2e new r2e@iankelling.org
775 # that initializes files, and sets default email.
776 # symlink to the config doesnt work, so I copied it to /p/c
777 # and then use cli option to specify explicit path.
778 # Only option changed from default config is to set
779 # force-from = True
780 #
781 # or else for a few feeds, the from address is set by the feed, and
782 # if I fail delivery, then I send a bounce message to that from
783 # address, which makes me be a spammer.
784
785 r2e add $1 "$2" $1@r2e.iankelling.org
786 # get up to date and dont send old entries now:
787 r2e run --no-send $1
788 }
789 r2e() { command r2e -d /p/c/rss2email.json -c /p/c/rss2email.cfg "$@"; }
790
791 rspicy() { # usage: HOST DOMAIN
792 # connect to spice vm remote host. use vspicy for local host
793 local port
794 # shellcheck disable=SC2087
795 port=$(ssh $1<<EOF
796 sudo virsh dumpxml $2|grep "<graphics.*type='spice'" | \
797 sed -rn "s/.*port='([0-9]+).*/\1/p"
798 EOF
799 )
800 if [[ $port ]]; then
801 spicy -h $1 -p $port
802 else
803 echo "error: no port found. check that the domain is running."
804 fi
805 }
806
807
808 scssl() {
809 # s gem install scss-lint
810 pushd /a/opt/thoughtbot-guides
811 git pull --stat
812 popd
813 scss-lint -c /a/opt/thoughtbot-guides/style/sass/.scss-lint.yml "$@"
814 }
815
816 skbrc() {
817 sk -e 2120,245 /b/ds/brc /b/ds/brc2
818 }
819
820 skaraoke() {
821 local tmp out
822 out=${2:-${1%.*}.sh}
823 tmp=$(mktemp -d)
824 script -t -c "mpv --no-config --no-resume-playback --no-terminal --no-audio-display '$1'" $tmp/typescript 2>$tmp/timing
825 # todo, the current sleep seems pretty good, but it
826 # would be nice to have an empirical measurement, or
827 # some better wait to sync up.
828 #
829 # note: --loop-file=no prevents it from hanging if you have that
830 # set to inf the mpv config.
831 # --loop=no prevents it from exit code 3 due to stdin if you
832 # had it set to inf in mpv config.
833 #
834 # args go to mpv, for example --volume=80, 50%
835 cat >$out <<EOFOUTER
836 #!/bin/bash
837 trap "trap - TERM && kill 0" INT TERM ERR; set -e
838 ( sleep .2; scriptreplay <( cat <<'EOF'
839 $(cat $tmp/timing)
840 EOF
841 ) <( cat <<'EOF'
842 $(cat $tmp/typescript)
843 EOF
844 ))&
845 base64 -d - <<'EOF'| mpv --loop=no --loop-file=no --no-terminal --no-audio-display "\$@" -
846 $(base64 "$1")
847 EOF
848 kill 0
849 EOFOUTER
850 rm -r $tmp
851 chmod +x $out
852 }
853
854 smeld() { # ssh meld usage host1 host2 file
855 meld <(ssh $1 cat $3) <(ssh $2 cat $3)
856 }
857
858 spd() {
859 PATH=/usr/local/spdhackfix:$PATH command spd "$@"
860 }
861
862 spend() {
863 s systemctl suspend
864 }
865
866 # ssh, copy my universal config over if needed.
867
868 # By default .bashrc is sourced for ALL ssh commands. This is wonky.
869 # Normally, this file is not sourced when a script is run, but we can
870 # override that by having #!/bin/bash -l. I want the same thing for ssh
871 # commands. when a local script runs an ssh command, bashrc should not be
872 # sourced, unless we use a modified command.
873 #
874 # So, in my bashrc, test for conditions of noninteractive ssh and return
875 # if so. And we don't keep the rest of the code in .bashrc, because
876 # even though we return, we parse the whole file which can cause errors
877 # as we develop it.
878 #
879 # To test for an overriding condition: bash builtin vars and env show no
880 # difference in ssh vs local, except shell level which is not
881 # reliable. one option is to use an environment variable. env variables
882 # sent across ssh are strictly limited. We could override an obscure
883 # unused LC_var, like telephone, but I don't want to run into some edge
884 # case where that messes things up. I choose to set SendEnv and
885 # AcceptEnv ssh config vars to allow the environment variable BRC to
886 # propagate across ssh, and for hosts I don't control, I start an inner
887 # shell with it set, which doubles up as a way to have a nondefault
888 # bashrc.
889 sl() {
890 # inspired from https://github.com/Russell91/sshrc
891
892
893 local args info_date info_t type now tmp tmp2 old sshinfo cmd haveinfo dorsync info_sec
894 declare -a args tmpa
895 now=$(date +%s)
896
897 # ssh [-1246Antivivisectionist] [-b bind_address] [-c cipher_spec] [-D [bind_address:]port]
898 # [-E log_file] [-e escape_char] [-F configfile] [-I pkcs11] [-i identity_file] [-L address]
899 # [-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-p port] [-Q query_option]
900 # [-R address] [-S ctl_path] [-W host:port] [-w local_tun[:remote_tun]] [user@]hostname
901 # [command]
902
903 while [[ $1 ]]; do
904 case "$1" in
905 -[1246AaCfGgKkMNnqsTtVvXxYy])
906 args+=("$1"); shift
907 ;;
908 -[bcDEeFIiLlmOopQRSWw]*)
909 # -oOption etc is valid
910 if (( ${#1} >= 3 )); then
911 args+=("$1"); shift
912 else
913 args+=("$1" "$2"); shift 2
914 fi
915 ;;
916 *)
917 break
918 ;;
919 esac
920 done
921 remote="$1"; shift
922 if [[ ! $remote ]]; then
923 echo $0: error hostname required >&2
924 return 1
925 fi
926 dorsync=false
927 haveinfo=false
928 tmpa=(/p/sshinfo/???????????"$remote")
929 sshinfo=${tmpa[0]}
930 if [[ -e $sshinfo ]]; then
931 haveinfo=true
932 fi
933 if $haveinfo; then
934 tmp=${sshinfo[0]##*/}
935 tmp2=${tmp::11}
936 type=${tmp2: -1}
937 if [[ $type == b ]]; then
938 info_sec=${tmp::10}
939 if (( $(stat -c%Y /b/ds/brc) > info_sec || $(stat -c%Y /b/ds/.bashrc) > info_sec )); then
940 dorsync=true
941 rm -f $sshinfo
942 fi
943 fi
944 else
945 dorsync=true
946 # use this weird yes thing to ensure we know ssh succeeded
947 if ! tmp=$(command ssh "${args[@]}" "$remote" "if test -e /a/bin/ds/.bashrc -a -L .bashrc; then echo yes; fi"); then
948 echo failed sl test. doing plain ssh -v
949 command ssh -v "${args[@]}" "$remote"
950 fi
951 if [[ $tmp == yes ]]; then
952 type=a
953 else
954 type=b
955 fi
956 fi
957 if [[ $type == b ]] && $dorsync; then
958 if ! RSYNC_RSH="ssh ${args[*]}" rsync -rptL /b/ds/sl/.iank "$remote":; then
959 echo WARNING: rsync failed. remove $sshinfo to try again
960 fi
961 fi
962 if $dorsync || ! $haveinfo; then
963 sshinfo=/p/sshinfo/$now$type"$remote"
964 touch $sshinfo
965 chmod 666 $sshinfo
966 fi
967 if [[ $type == b ]]; then
968 if $dorsync; then
969 RSYNC_RSH="ssh ${args[*]}" rsync -rptL /b/ds/sl/.iank "$remote":
970 fi
971 if (( ${#@} )); then
972
973 # Theres a couple ways to do this. im not sure whats best,
974 # but relying on bash 4.4+ escape quoting seems most reliable.
975 command ssh "${args[@]}" "$remote" \
976 BRC=t bash -c '.\ .iank/.bashrc\;"\"\$@\""' bash ${@@Q}
977 elif [[ ! -t 0 ]]; then
978 # This case is when commands are being piped to ssh.
979 # Normally, no bashrc gets sourced.
980 # But, since we are doing all this, lets source it because we can.
981 cat <(echo . .iank/.bashrc) - | command ssh "${args[@]}" "$remote" BRC=t bash
982 else
983 command ssh -t "${args[@]}" "$remote" BRC=t INPUTRC=.iank/.inputrc bash --rcfile .iank/.bashrc
984 fi
985 else
986 if [[ -t 0 ]]; then
987 BRC=t command ssh "${args[@]}" "$remote" ${@@Q}
988 else
989 command ssh "${args[@]}" "$remote" BRC=t bash -l
990 fi
991 fi
992 }
993 sss() { # ssh solo
994 sl -oControlMaster=no -oControlPath=/ "$@"
995 }
996 # kill off old shared socket then ssh
997 ssk() {
998 m ssh -O exit "$@"
999 m sl "$@"
1000 }
1001 # plain limited ssh
1002 ssh() {
1003 BRC=t command ssh "$@"
1004 }
1005
1006
1007 # mail related
1008 testmail() {
1009 declare -gi _seq; _seq+=1
1010 echo "test body" | m mail -s "test mail from $HOSTNAME, $_seq" "${@:-root@localhost}"
1011 # for testing to send from an external address, you can do for example
1012 # -fian@iank.bid -aFrom:ian@iank.bid web-6fnbs@mail-tester.com
1013 # note in exim, you can retry a deferred message
1014 # s exim -M MSG_ID
1015 # MSG_ID is in /var/log/exim4/mainlog, looks like 1ccdnD-0001nh-EN
1016 }
1017
1018 # to test sieve, use below command. for fsf mail, see offlineimap-sync script
1019 # make modifications, then copy to live file, use -eW to actually modify mailbox
1020 #
1021 # Another option is to use sieve-test SCRIPT MAIL_FILE. note,
1022 # sieve-test doesnt know about envelopes, Im not sure if sieve-filter does.
1023
1024 # sieve with output filter. arg is mailbox, like INBOX.
1025 # This depends on dovecot conf, notably mail_location in /etc/dovecot/conf.d/10-mail.conf
1026
1027 _dosieve() {
1028 sieve-filter "$@" 2> >(head; tail) >/tmp/testsieve.log && sed -rn '/^Performed actions:/,/^[^ ]/{/^ /p}' /tmp/testsieve.log | sort | uniq -c
1029 }
1030
1031 # always run this first, edit the test files, then run the following
1032 testsieve() {
1033 _dosieve ~/sieve/maintest.sieve ${1:-INBOX} delete
1034 }
1035 runsieve() {
1036 c ~/sieve; cp personal{test,}.sieve; cp lists{test,}.sieve; cp personalend{test,}.sieve
1037 _dosieve ~/sieve/main.sieve -eW ${1:-INBOX} delete
1038 }
1039
1040 # mail related
1041 testexim() {
1042 # testmail above calls sendmail, which is a link to exim/postfix.
1043 # its docs dont say a way of adding an argument
1044 # to sendmail to turn on debug output. We could make a wrapper, but
1045 # that is a pain. Exim debug args are documented here:
1046 # http://www.exim.org/exim-html-current/doc/html/spec_html/ch-the_exim_command_line.html
1047 #
1048 # http://www.exim.org/exim-html-current/doc/html/spec_html/ch-building_and_installing_exim.html
1049 # note, for exim daemon, you can turn on debug options by
1050 # adding -d, etc to COMMONOPTIONS in
1051 # /etc/default/exim4
1052 #
1053 # to specify recipients other than those in to, cc, bcc, you can use the cli args, eg:
1054 # exim -i 'test@zroe.org, t2@zroe.org' <<'EOF'
1055 #
1056 #
1057 exim -d -t <<'EOF'
1058 From: i@dmarctest.b8.nz
1059 To: mailman@dev.fsf.org
1060 Subject: test2
1061 Reply-to: rtest@iankelling.org
1062
1063 This is a test message.
1064 EOF
1065 }
1066
1067 # toggle keyboard
1068 tk() {
1069 # based on
1070 # https://askubuntu.com/questions/160945/is-there-a-way-to-disable-a-laptops-internal-keyboard
1071 id=$(xinput --list --id-only 'AT Translated Set 2 keyboard')
1072 if xinput list | grep -F '∼ AT Translated Set 2 keyboard' &>/dev/null; then
1073 echo enabling keyboard
1074 # find the first slave keyboard number, they are all the same in my output.
1075 # if they werent, worst case we would need to save the slave number somewhere
1076 # when it got disabled.
1077 slave=$(xinput list | sed -n 's/.*slave \+keyboard (\([0-9]*\)).*/\1/p' | head -n1)
1078 xinput reattach $id $slave
1079 else
1080 xinput float $id
1081 fi
1082 }
1083
1084 tm() {
1085 # timer in minutes
1086 # --no-config
1087 (sleep $(calc "$* * 60") && mpv --no-config --volume 50 /a/bin/data/alarm.mp3) > /dev/null 2>&1 &
1088 }
1089
1090 trg() { transmission-remote-gtk&r; }
1091 trc() {
1092 # example, set global upload limit to 100 kilobytes:
1093 # trc -u 100
1094 TR_AUTH=":$(jq -r .profiles[0].password ~/.config/transmission-remote-gtk/config.json)" transmission-remote transmission.lan -ne "$@"
1095 }
1096
1097
1098 tu() {
1099 local s dir
1100 dir="$(dirname "$1")"
1101 if [[ -e $1 && ! -w $1 || ! -w $(dirname "$1") ]]; then
1102 s=s;
1103 fi
1104 # full path for using in some initial setup steps
1105 $s /a/exe/teeu "$@"
1106 }
1107
1108 vpncmd() {
1109 #m s nsenter -t $(pgrep -f "/usr/sbin/openvpn .* --config /etc/openvpn/.*pia.conf") -n -m "$@"
1110 m s nsenter -t $(pgrep -f "/usr/sbin/openvpn .* --config /etc/openvpn/.*client.conf") -n -m "$@"
1111 }
1112 vpnf() {
1113 vpncmd gksudo -u iank "firefox -no-remote -P vpn" &r
1114 }
1115 vpni() {
1116 vpncmd gksudo -u iank "$*"
1117 }
1118 vpnbash() {
1119 vpncmd bash
1120 }
1121
1122
1123 vpn() {
1124 if [[ -e /lib/systemd/system/openvpn-client@.service ]]; then
1125 local vpn_service=openvpn-client
1126 else
1127 local vpn_service=openvpn
1128 fi
1129
1130 [[ $1 ]] || { echo need arg; return 1; }
1131 journalctl --unit=$vpn_service@$1 -f -n0 &
1132 s systemctl start $vpn_service@$1
1133 # sometimes the ask-password agent does not work and needs a delay.
1134 sleep .5
1135 # https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=779240
1136 # noticed around 8-2017 after update from around stretch release
1137 # on debian testing, even though the bug is much older.
1138 s systemd-tty-ask-password-agent
1139 }
1140
1141 vpnoff() {
1142 [[ $1 ]] || { echo need arg; return 1; }
1143 if [[ -e /lib/systemd/system/openvpn-client@.service ]]; then
1144 local vpn_service=openvpn-client
1145 else
1146 local vpn_service=openvpn
1147 fi
1148 s systemctl stop $vpn_service@$1
1149 }
1150 vpnoffc() { # vpn off client
1151 ser stop openvpn-nn@client
1152 }
1153 vpnc() {
1154 ser start openvpn-nn@client
1155 }
1156
1157
1158 vspicy() { # usage: VIRSH_DOMAIN
1159 # connect to vms made with virt-install
1160 spicy -p $(sudo virsh dumpxml "$1"|grep "<graphics.*type='spice'"|\
1161 sed -r "s/.*port='([0-9]+).*/\1/")
1162 }
1163
1164 wian() {
1165 cat-new-files /m/4e/INBOX/new
1166 }
1167
1168 wtr() { curl wttr.in/boston; }
1169
1170 xevkb() { xev -event keyboard; }
1171
1172 # * misc stuff
1173
1174 # from curl cheat.sh/:bash_completion
1175 _cheatsh_complete_curl()
1176 {
1177 local cur prev opts
1178 _get_comp_words_by_ref -n : cur
1179
1180 COMPREPLY=()
1181 #cur="${COMP_WORDS[COMP_CWORD]}"
1182 prev="${COMP_WORDS[COMP_CWORD-1]}"
1183 opts="$(curl -s cheat.sh/:list | sed s@^@cheat.sh/@)"
1184
1185 if [[ ${cur} == cheat.sh/* ]] ; then
1186 COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
1187 __ltrim_colon_completions "$cur"
1188 return 0
1189 fi
1190 }
1191 complete -F _cheatsh_complete_curl curl
1192
1193
1194
1195
1196 reset-konsole() {
1197 # we also have a file in /a/c/...konsole...
1198 local f=$HOME/.config/konsolerc
1199 setini DefaultProfile profileian.profile "Desktop Entry" $f
1200 setini Favorites profileian.profile "Favorite Profiles" $f
1201 setini ShowMenuBarByDefault false KonsoleWindow $f
1202 setini TabBarPosition Top TabBar $f
1203 }
1204
1205 reset-sakura() {
1206 while -r read k v; do
1207 # shellcheck disable=SC2154
1208 setini $k $v sakura /a/c/subdir_files/.config/sakura/sakura.conf
1209 done <<'EOF'
1210 colorset1_back rgb(33,37,39
1211 less_questions true
1212 audible_bell No
1213 visible_bell No
1214 disable_numbered_tabswitch true
1215 scroll_lines 10000000
1216 scrollbar true
1217 EOF
1218 }
1219
1220 reset-xscreensaver() {
1221 # except for spash, i set these by setting gui options in
1222 # xscreensaver-command -demo
1223 # then finding the corresponding option in .xscreensaver
1224 # spash, i happened to notice in .xscreensaver
1225 #
1226 # dpmsOff, monitor doesnt come back on using old free software supported nvidia card
1227 cat > /home/iank/.xscreensaver <<'EOF'
1228 mode: blank
1229 dpmsEnabled: True
1230 dpmsStandby: 0:02:00
1231 dpmsSuspend: 0:03:00
1232 dpmsOff: 0:00:00
1233 timeout: 0:02:00
1234 lock: True
1235 lockTimeout: 0:03:00
1236 splash: False
1237 EOF
1238
1239 }
1240
1241
1242 # * stuff that makes sense to be at the end
1243 if [[ "$SUDOD" ]]; then
1244 cd "$SUDOD"
1245 unset SUDOD
1246 elif [[ -d /a ]] && [[ $PWD == "$HOME" ]] && [[ $- == *i* ]]; then
1247 cd /a
1248 fi
1249
1250
1251 # best practice
1252 unset IFS
1253
1254
1255 # for mitmproxy to get a newer python.
1256 # commented until i want to use it because it
1257 # noticably slows bash startup
1258 #
1259
1260 mypyenvinit () {
1261 if [[ $EUID == 0 || ! -e ~/.pyenv/bin ]]; then
1262 echo "error: dont be root. make sure pyenv is installed"
1263 return 1
1264 fi
1265 export PATH="$HOME/.pyenv/bin:$PATH"
1266 eval "$(pyenv init -)"
1267 eval "$(pyenv virtualenv-init -)"
1268 }
1269
1270
1271 export GOPATH=$HOME/go
1272 path-add $GOPATH/bin
1273 path-add /usr/local/go/bin
1274
1275 # I have the git repo and a release. either one should work.
1276 # I have both because I was trying to solve an issue that
1277 # turned out to be unrelated.
1278 # ARDUINO_PATH=/a/opt/Arduino/build/linux/work
1279 export ARDUINO_PATH=/a/opt/arduino-1.8.9
1280
1281 # They want to be added to the start, but i think
1282 # that should be avoided unless we really need it.
1283 path-add --end ~/.npm-global
1284
1285 path-add --end $HOME/.cargo/bin
1286
1287 # taken from default changes to bashrc and bash_profile
1288 path-add --end $HOME/.rvm/bin
1289 path-add --end $HOME/.gem/ruby/2.3.0/bin
1290
1291
1292 export BASEFILE_DIR=/a/bin/fai-basefiles
1293
1294 #export ANDROID_HOME=/a/opt/android-home
1295 # https://f-droid.org/en/docs/Installing_the_Server_and_Repo_Tools/
1296 #export USE_SDK_WRAPPER=yes
1297 #PATH=$PATH:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools
1298
1299 # didnt get drush working, if I did, this seems like the
1300 # only good thing to include for it.
1301 # Include Drush completion.
1302 # if [ -f "/home/ian/.drush/drush.complete.sh" ] ; then
1303 # source /home/ian/.drush/drush.complete.sh
1304 # fi
1305
1306
1307 # https://wiki.archlinux.org/index.php/Xinitrc#Autostart_X_at_login
1308 # i added an extra condition as gentoo xorg guide says depending on
1309 # $DISPLAY is fragile.
1310 if [[ ! $DISPLAY && $XDG_VTNR == 1 ]] && shopt -q login_shell && isarch; then
1311 exec startx
1312 fi
1313
1314
1315 # ensure no bad programs appending to this file will have an affect
1316 return 0