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