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