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