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