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