+# false positives: tidy, checked syscalls. rest are preferences.
+
+[-CodeLayout::RequireTidyCode]
+[-InputOutput::RequireCheckedSyscalls]
+[-ValuesAndExpressions::ProhibitVersionStrings]
+[-Modules::ProhibitAutomaticExportation]
+[-Variables::ProhibitPackageVars]
+[-ControlStructures::ProhibitPostfixControls]
+[-ValuesAndExpressions::ProhibitImplicitNewlines]
+[-ValuesAndExpressions::RequireQuotedHeredocTerminator]
[-Subroutines::RequireArgUnpacking]
[-Subroutines::RequireFinalReturn]
+[-RegularExpressions::RequireExtendedFormatting]
+[-ControlStructures::ProhibitCascadingIfElse]
+[-Variables::ProhibitConditionalDeclarations]
+[-Modules::RequireBarewordIncludes]
+[-Variables::ProhibitPunctuationVars]
+
+[Subroutines::ProhibitExcessComplexity]
+add_themes = complex_mess
+[ControlStructures::ProhibitDeepNests]
+add_themes = complex_mess
+[Subroutines::ProhibitManyArgs]
+add_themes = complex_mess
$sdrun_prefix systemd-run $sdrun_args --unit "$unit_name" --wait --collect "$cmd" "$@" || ret=$?
# The sleep lets the journal output its last line
# before the prompt comes up.
- sleep .5
+ sleep 1
kill $jr_pid &>/dev/null ||:
unset jr_pid
fg &>/dev/null ||:
-o -name .hg -prune -o -name .editor-backups -prune \
-o -name .undo-tree-history -prune \) \! -type d 2>/dev/null
}
-# fas = find all shebang. filter by the last word in the shebang path
+# fas = find all shebang. filter by the last word in the shebang path.
# usage: $0 INTERPRETER_BINARY_NAME [FIND_INITIAL_ARGS...]
fas() {
local name="$1"
shift
- find "$@" -not \( -name .svn -prune -o -name .git -prune \
+ find "$@" \! \( -name .svn -prune -o -name .git -prune \
-o -name .hg -prune -o -name .editor-backups -prune \
-o -name .undo-tree-history -prune \) \! -type d \
-exec awk 'FNR==1 && /^#![^ ]*\/'"$name( |$)/ {print FILENAME; nextfile}" {} + 2>/dev/null
- }
+}
# like faf, but sort by modification time. like lt()
faft() {
find "$@" -not \( -name .svn -prune -o -name .git -prune \
-o -name .hg -prune -o -name .editor-backups -prune \
- -o -name .undo-tree-history -prune \) \! -type d \
+ -o -name .undo-tree-history -prune \) -type f \
-printf "%T@ %P\n" | sort -n | cut -d' ' -f2-
}
whatismyip() { pubip; }
-q() { # quietly start / launch a program
+q() { # quietly start / launch a program, as long as it doesn't fail within a second.
"$@" &> /dev/null & disown
# online, I ran into a version that runs in a subshell with ( ), I
# suppose that might quiet some programs that try to talk to the tty
"$@" | sponge "$file"
}
+# in-place perltidy with settings i like.
+pltidy() {
+ ri perltidy -i=2 -l=200 -pt=2 -nsfs -ce -conv -st --valign-exclusion-list='if unless and or err for foreach while until' "$@"
+}
+
# rsync with nice defaults.
# scp is a bit insecure and deprecated.
sp() {
}
-# usage $0 PID...
-maxpri() {
- # we try process group (-g, -P) to hit related processes. If this fails, fall back to pid: (-p, -p)
- if ! s renice -20 -g "$@"; then
- m s renice -20 -p "$@"
- m s ionice -c1 -n0 -p "$@"
- return 0
- fi
- s ionice -c1 -n0 -P "$@"
-}
# usage $0 PID...
minpri() {
m s ionice -c3 -p "$@"
return 0
fi
- s ionice -c3 -P "$@"
+ m s ionice -c3 -P "$@"
}
-# Prefix for launching a command:
+
+
+# Prefix for launching a command (missing the :
# shellcheck disable=SC2034 # false positive
maxpri="s nice -n-40 ionice -c1 -n0"
# shellcheck disable=SC2034 # false positive
wg-log-on() {
e module wireguard +p | s tee /sys/kernel/debug/dynamic_debug/control
- }
+}
wg-log-off() {
e module wireguard -p | s tee /sys/kernel/debug/dynamic_debug/control
}
+
+### begin debug-setx related functions ###
+#
+# usage: debug-setx
+#
+# Print executing commands like "set -x", but:
+#
+# - Skips printing many boring/redundant lines. There are related
+# functions below to modify/toggle what gets printed.
+#
+# - Related function h() to prompt before executing printed command.
+#
+# Printing of uninteresting commands can be limited:
+#
+# 1: Do not print command when stack depth is >= debug_max_stack_depth.
+#
+# 2: Allow printing in specific functions with setx-func (see its doc below).
+#
+# There is a hard-coded list of commands to skip or maybe skip. You can
+# improve this.
+#
+debug-setx() {
+ local existing_debug_trap
+
+ # Note on commands we skip printing:
+ # - read ends up being what is shown for 'while read' loops.
+
+ # for inheriting debug in subshells
+ shopt -s extdebug
+
+ debug_prompt=false
+ debug_skip=false
+ debug_force_print=false
+
+ existing_debug_trap=$(trap -p DEBUG 2>&1)
+ if [[ $existing_debug_trap && $existing_debug_trap != *_debug-setx-func ]]; then
+ trap "$existing_debug_trap; _debug-setx-func" DEBUG
+ else
+ trap _debug-setx-func DEBUG
+ fi
+}
+# internal function called via debug-setx trap.
+_debug-setx-func() {
+ local doprint=false random_delimiter func cmd col debug_cmd
+
+ if [[ $debug_max_stack_depth ]]; then
+ funcname_count_max=$(( debug_max_stack_depth + 1 ))
+ else
+ # within 0 func level, FUNCNAME has 2 in here, eg debug-setx-func main.
+ funcname_count_max=99999
+ fi
+
+ if [[ $BASH_SUBSHELL != [01] ]]; then
+ return 0
+ fi
+
+ if $debug_skip; then
+ debug_skip=false
+ return 0
+ fi
+
+ if $debug_prompt; then
+ doprint=true
+ fi
+
+ if $debug_force_print; then
+ debug_force_print=false
+ doprint=true
+ fi
+
+ if $debug_print_default; then
+
+ ## block for debug_print_funcs
+ if ! $doprint; then
+ for func in ${debug_print_funcs[@]}; do
+ if [[ $func == "${FUNCNAME[1}" ]]; then
+ doprint=true
+ break
+ fi
+ done
+ fi
+
+ ## block for default command & function ignoring
+ if ! $doprint && (( ${#FUNCNAME[*]} <= funcname_count_max )); then
+ # debug
+ #e "${FUNCNAME[*]} ${#FUNCNAME[*]} <= $funcname_count_max"
+ case $BASH_COMMAND in
+ e\ *|err\ *|echo\ *|printf\ *|read\ *|h|ux|ux\ *)
+ : ;;
+ for\ *)
+ # try to print just the first for loop iteration.
+ _debug_setx_cur_for="$BASH_COMMAND ${BASH_LINENO[0]} ${FUNCNAME[1]}"
+ if [[ $_debug_setx_cur_for != "$_debug_setx_last_for" ]]; then
+ doprint=true
+ fi
+ _debug_setx_last_for="$_debug_setx_cur_for"
+ ;;
+ *)
+ doprint=true
+ ;;
+ esac
+ fi
+
+ fi
+
+ if $doprint; then
+ # Expanding $1 will be empty, so skip expansion in that case, and some others.
+ #
+ # TODO: we should be able to grab $1 from the function tracing facilities.
+ #
+ # Note, we could split the command up and expand other parts
+ # but I'm not going to bother.
+ if [[ $BASH_COMMAND != *\$[0-9]* && $BASH_COMMAND != *\`* && $BASH_COMMAND != *\$\(* && $BASH_COMMAND == *\$* ]]; then
+ random_delimiter=$RANDOM$RANDOM$RANDOM
+ # shellcheck disable=SC1003
+ _d="$BASH_COMMAND" _d="${_d//'\\'/SUBfopguensOfRifejmu${random_delimiter}SUB}" _d="${_d//\\[adehHjlnrstT@AuvVwW\!\#\$[\]]/\\&}" _d="${_d//\\D\{*\}/\\&}" _d="${_d//\\[012][0-9][0-9]/\\&}" _d="${_d//\\3[0-6][0-9]/\\&}" _d="${_d//\\37[0-7]/\\&}" _d="${_d//SUBfopguensOfRifejmu${random_delimiter}SUB/'\\\\'}"
+ cmd="${_d@P}"
+ else
+ cmd="$BASH_COMMAND"
+ fi
+ [[ $COLUMNS ]] || { _s=$(stty size); COLUMNS=${_s#* }; }
+ if [[ $COLUMNS == *[0-9]* ]]; then
+ # generally fill up 2 rows
+ col=$(( COLUMNS * 2 - 20 ))
+ else
+ col=150
+ fi
+ if (( ${#cmd} > col )); then
+ cmd="$(( ${#cmd} - col)) cut: ${cmd:0:col}"
+ fi
+ echo "+ $cmd" >&2
+ fi
+
+ if $debug_prompt; then
+ # we can type in commands here to inspect the program state.
+ read -r -e -p "DEBUG $ " debug_cmd
+ while [[ $debug_cmd ]]; do
+ eval $debug_cmd
+ read -r -e -p "DEBUG $ " debug_cmd
+ done
+ debug_prompt=false
+ fi
+}
+
+# usage: ux [COMMAND...]
+#
+# disable/unset debug-setx default command printing. Runs COMMAND if
+# given. Command arg exists only because the args would be otherwise
+# unused.
+ux() {
+ debug_print_default=false
+ if [[ $1 ]]; then "$@"; fi
+}
+
+# usage: u1 [COMMAND...]
+#
+# Disable debug-setx printing just for the next command.
+u1() {
+ # we have this strange logic because [[ is a command, easier to not
+ # have that be between debug_skip=true and $@ and trigger a debug
+ # trap.
+ if [[ $1 ]]; then
+ debug_skip=true
+ "$@"
+ else
+ debug_skip=true
+ fi
+}
+
+# usage: dx [COMMAND...]
+#
+# Undo ux() and reenable debug-setx printing.
+dx() {
+ if [[ $1 ]]; then
+ debug_print_default=true
+ "$@"
+ else
+ debug_print_default=true
+ fi
+}
+
+# usage: d1 [COMMAND...]
+#
+# For just one command, reenable debug-setx printing.
+d1() {
+ if [[ $1 ]]; then
+ debug_force_print=true
+ "$@"
+ else
+ debug_force_print=true
+ fi
+}
+
+
+
+# usage: setx-func [FUNCTION...]
+#
+# Do debug-setx printing within current function or FUNCTION(s) even
+# when called with function stack size greater than
+# $debug_max_stack_depth.
+setx-func() {
+ local new_func new_funcs found existing_func
+ if [[ ! -v debug_print_funcs ]]; then
+ debug_print_funcs=()
+ fi
+
+ e "${FUNCNAME[*]}"
+ if [[ $1 ]]; then
+ new_funcs="$*"
+ else
+ new_funcs="${FUNCNAME[0]}"
+ fi
+ for new_func in $new_funcs; do
+ found=false
+ for existing_func in ${debug_print_funcs[@]}; do
+ if [[ $existing_func == "$new_func" ]]; then
+ found=true
+ break
+ fi
+ done
+ if $found; then
+ break
+ fi
+ debug_print_funcs+=($new_func)
+ done
+}
+
+### end debug-setx related functions ###
+
+## begin debug-setx background / development notes
+#
+# I often end up writing little 5-10 line scripts. To log what they are doing,
+# I was annoyed with the available options. #1 There is set -x, which usually ends up
+# being > 50% useless lines, very anoying. #2
+# m() { printf "%s\n" "$*";
+#"$@"; } that annoyingly conflicts with command
+# redirected output, and I constantly forget to add it.
+#
+# Better option: debug trap, where we can print $BASH_COMMAND. The main
+# annoying thing about this is that $BASH_COMMAND doesn't have expanded
+# variables.
+#
+# options to expand variables in a $BASH_COMMAND:
+#
+# 1. get bash to do readline's shell-expand-line. I know a hacky way
+# with read, but it wasn't reliable when I tried it in a
+# prompt_command. I could probably create a c program that uses readline
+# to do it pretty easily
+#
+# 2. Use the prompt expansion features @P, but first escape the special
+# prompt characters if there are any. This was the option I went
+# with. It has a small flaw that I realized without calling a regex
+# substitution program, my escaping is not perfect: I temporarily insert
+# a long random string to identify "\\", but it is possible this string
+# could exist in the command and then I would improperly replace
+# it. However, my use case is simply viewing commands I intend to run
+# and I don't see any reason I would intend to run a command with that
+# or that even if I did, it would cause any serious problem to have it
+# be incorrectly displayed.
+#
+# NOTE: One imperfection with both of these, is that we don't want to
+# expand $() or ``, so I look for those chars and then avoid doing it. I
+# think the only way to avoid this would be to modify bash itself in
+# order to do shell-expand-line and then use the result, just as if you
+# pressed the key for it.
+#
+# \\ -> \\\\ : creates problem matching eg: \e
+#
+# alternate:
+#
+# \134 -> RANDOM_LONG_STRING
+#
+# \\ -> \134\134 : creates problem matching \134, we need to match \134!(\134), solved by the RANDOM_LONG_STRING
+#
+# \a -> \134a
+#
+# \D{*} and \123 -> \\&
+#
+# RANDOM_LONG_STRING -> \\134
+#
+# alternate, best:
+#
+# \\ -> RANDOM_LONG_STRING
+#
+# \a -> \\a
+#
+# \D{*} and \123 -> \\&
+#
+# RANDOM_LONG_STRING -> \\\\
+#
+# # incrementally built up test cases, where the output is expected to be the same as the initial _d
+#
+# _d='ok\\\\jyes'; _d="${_d//'\\'/SUBfopguensOfRifejmuSUB}" _d="${_d//\\[adehHjlnrstT@AuvVwW\!\#\$[\]]/\\&}" _d="${_d//SUBfopguensOfRifejmuSUB/'\\\\'}"; e "$_d + ${_d@P}"
+#
+# _d='ok\D{z_ds}yes'; _d="${_d//'\\'/SUBfopguensOfRifejmuSUB}" _d="${_d//\\[adehHjlnrstT@AuvVwW\!\#\$[\]]/\\&}" _d="${_d//\\D\{*\}/\\&}" _d="${_d//SUBfopguensOfRifejmuSUB/'\\\\'}"; e "$_d + ${_d@P}"
+#
+# _d='ok\144ye\134s'; _d="${_d//'\\'/SUBfopguensOfRifejmuSUB}" _d="${_d//\\[adehHjlnrstT@AuvVwW\!\#\$[\]]/\\&}" _d="${_d//\\D\{*\}/\\&}" _d="${_d//\\[012][0-9][0-9]/\\&}" _d="${_d//\\3[0-6][0-9]/\\&}" _d="${_d//\\37[0-7]/\\&}" _d="${_d//SUBfopguensOfRifejmuSUB/'\\\\'}"; e "$_d + ${_d@P}"
+#
+#
+# random interesting script:
+# x=4
+# echo "\$x ${BASH_COMMAND@P}"
+# Warning: Program '/bin/bash' crashed.
+#
+## end debug-setx background / development notes
+
+
# * stuff that makes sense to be at the end
# note, if we unset IFS, that will mess up completion scripts which
# Alt is just the other host that takes snapshots
# besides the local host.
btrbk-host-debug() {
-local host remote alt f
+ local host remote alt f
remote=b8.nz
alt=sywg.b8.nz
/p/c/subdir_files
)
a="-ahviSAXPH --specials --devices --delete --delete-excluded --relative --exclude-from=/p/c/li-rsync-excludes"
- for h in li je bk; do
+ for h in li bk; do
m s rsync "$@" $a ${fs[@]} /p/c/machine_specific/$h root@$h.b8.nz:/
## only li is debian11
#p[0]=/a/opt/emacs-trisuqel10
local -a fs
local -i ret=0
fs=(/a/bin /a/exe /a/h /a/c /p/c/machine_specific/vps{,.hosts}
- /a/f/ans/roles/prom_export/files/simple/usr/local/bin/fsf-install-node-exporter
- )
+ /a/f/ans/roles/prom_export/files/simple/usr/local/bin/fsf-install-node-exporter
+ )
a="-ahviSAXPH --specials --devices --delete --relative --exclude-from=/p/c/li-rsync-excludes"
ret=0
m rsync "$@" $a ${fs[@]} /p/c/machine_specific/bk root@bk.b8.nz:/ || ret=$?
local -a fs
local -i ret=0
fs=(/a/bin /a/exe /a/h /a/c /p/c/machine_specific/vps{,.hosts}
- /a/f/ans/roles/prom_export/files/simple/usr/local/bin/fsf-install-node-exporter
- )
+ /a/f/ans/roles/prom_export/files/simple/usr/local/bin/fsf-install-node-exporter
+ )
a="-ahviSAXPH --specials --devices --delete --relative --exclude-from=/p/c/li-rsync-excludes"
ret=0
bindpushb8
# for wireguard configs
- ssh iank@li.b8.nz "conflink; ser reload wg-quick-mail"
+ ssh iank@li.b8.nz "conflink; ser reload wg-quick@mail"
wrt-setup
}
for h in ${root_hosts[@]}; do
root_hosts+=(${h}ex)
done
- root_hosts+=(cmc)
+ root_hosts+=(cmc wrtap w33)
work_hosts=(10.8.0.97 10.8.0.99)
EOF
done
+
+ cat >/p/c/machine_specific/frodo/filesystem/etc/dhcp/dhcpd.conf <<'EOF'
+# generated by hiup
+authoritative;
+#option dhcp-max-message-size 2048;
+use-host-decl-names on;
+
+subnet 10.0.0.0 netmask 255.255.0.0 {
+ range 10.0.0.100 10.0.0.199;
+ option routers 10.0.0.1;
+ option domain-name "b8.nz";
+ option domain-search "b8.nz";
+ option domain-name-servers 8.8.8.8;
+ option ntp-servers 0.ubuntu.pool.ntp.org, 1.ubuntu.pool.ntp.org, ntp.ubuntu.com;
+}
+
+default-lease-time 600;
+max-lease-time 7200;
+EOF
+
for host in ${!vpn_ips[@]}; do
if [[ ${root_hosts_a[$host]} ]]; then
continue
echo "EOF"
} | u /p/c/ptr-data
+ # this is for old setup where dhcp is done by cmc.
{
echo "cat <<EOF"
for host in ${!host_macs[@]}; do
} | u /p/c/dnsmasq-data
+ for host in ${!host_macs[@]}; do
+ if [[ ${host_macs[$host]} != *:* ]]; then continue; fi
+
+ ipsuf=${host_ips[$host]}
+ cat >>/p/c/machine_specific/frodo/filesystem/etc/dhcp/dhcpd.conf <<EOF
+host $host {
+ hardware ethernet ${host_macs[$host]};
+ fixed-address 10.0.0.$ipsuf;
+}
+EOF
+ done
+
#b8_ip=$(dig +short b8.nz @iankelling.org | tail -1)
# if our dynamic ip updates broke, set manually, eg:
b8_ip=108.26.192.250 # 72.74.193.xxx
EOF
for host in ${!nonvpn_ips[@]}; do
ipsuf=${nonvpn_ips[$host]}
- echo "$host A 10.2.0.$ipsuf"
+ echo "$host A 10.0.0.$ipsuf"
done
for host in ${!vpn_ips[@]}; do
ipsuf=${vpn_ips[$host]}
cat <<EOF
-$host A 10.2.0.$ipsuf
+$host A 10.0.0.$ipsuf
${host}wg A 10.8.0.$ipsuf
${host}vp A 10.5.5.$ipsuf
${host}tr A 10.174.$ipsuf.2
if ! s ip netns list | grep -Fx nonet &>/dev/null; then
s ip netns add nonet
fi
- mns $ns --net=/var/run/netns/nonet sudo -E -u iank /bin/bash
+ user=$USER
+ env-tmpf bash
+ mns-setup $ns
+ m sudm /usr/bin/nsenter --mount=/root/mount_namespaces/$ns --net=/var/run/netns/nonet sudo -u iank -i bash -c ". $tmpf"
lomh
}
# my profanity
#
+# usage: $0 [weeks]
myprof() {
+ local weeks
+ if [[ $1 ]]; then
+ weeks=$1
+ elif [[ $(date +%A) == Monday ]]; then
+ weeks=2
+ else
+ weeks=5
+ fi
+
pushd /home/iank/.local/share/profanity/chatlogs/iank_at_fsf.org/rooms/office_at_conference.fsf.org
logs=(*)
i=0
fi
# usually do this on monday, sometimes later
- if [[ $(date +%A) == Monday ]]; then
- min_date=$(date -d 'monday 2 weeks ago' +%s)
- else
- min_date=$(date -d 'monday 5 weeks ago' +%s)
- fi
+ min_date=$(date -d "monday $weeks weeks ago" +%s)
for (( ; i < logcount; i++ )); do
log_base=${logs[$i]}
day_logs=()
# could just get this in the first place, but i don't know if that
# is always the case.
procsf=$dir/${unit%.service}.service/cgroup.procs
- if [[ -s $procsf ]]; then
+ # note: ls will show the file as empty even though it isn't
+ if [[ -e $procsf ]]; then
pid=$(head -n1 $procsf)
else
pid=
vpni() {
local n="$1" ser_suf=tr
if [[ $n ]]; then ser_suf=nn; fi
+ vpnc $n
# m sudo nsenter --net=/var/run/netns/client sudo -u iank -i bash # for just the netns
sdncmd wg-quick-$ser_suf@client$n.service bash
}
local n="$1" ser_suf=tr
if [[ $n ]]; then ser_suf=nn; fi
unit=wg-quick-$ser_suf@client$n
- sudo -v
+ if [[ $EUID != 0 ]]; then
+ sudo -v
+ fi
if [[ $(systemctl is-active $unit) != active ]]; then
- s systemctl start $unit
+ m s systemctl start $unit
sleep 1
fi
}
alias rg=grr
fi
+# find all perl files
+fapl() {
+ fas perl \! -name '*.*'; faf \( -name '*.pl' -o -name '*.pm' \)
+}
+
+# rg perl files
+rgpl() {
+ rg "$@" $(fapl)
+}
+
# rg with respecting vcs ignore files
rgv() {
local path_arg ret=0
etc/systemd/resolved.conf.d/*)
restart_services[systemd-resolved]=t
;;
+ # todo: this isnt working
+ etc/dhcp/dhcpd.conf) restart_services[isc-dhcp-server]=t ;;
esac
# Previously did this with tar, but it doesn't
# update directory permissions.
sgo openvpn-client@hole
fi
+case $HOSTNAME in
+ $d_host)
+ sgo frodo-route
+ sgo isc-dhcp-server
+ # Avoid the dhcp on other hosts. it seems static ips could be
+ # configured but i'm not bothering.
+ pi dropbear-initramfs
+ ;;
+esac
+
############# begin syncthing setup ###########
case $HOSTNAME in
$d_host)
#m /a/bin/buildscripts/alacritty
#m /a/bin/buildscripts/kitty
-pi-nostart virtinst virt-manager
+# qemu & zsync are quickemu dependencies
+pi-nostart virtinst virt-manager qemu-system zsync
soff libvirtd
# i cant if this is whats causing it to start even though
# its disabled. note: it leaves around dnsmasq instances even
#
#
# initial config goes to /home/iank/.config/gh
-curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg \
- && sudo chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg \
- && echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null \
+curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/etc/apt/keyrings/githubcli-archive-keyring.gpg \
+ && sudo chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg \
+ && echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null \
&& sudo apt-get update \
&& sudo apt-get install gh -y
+# fix old path on old computers.
+sudo sed -ri 's,/usr/share/key,/etc/apt/key,' /etc/apt/sources.list.d/github-cli.list
### end gh ####
pi postgresql-common
sudo /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh -y noble
pi-nostart postgresql-$ver postgresql-doc-$ver
- # when we run it, do:
- #sudo -u postgres createuser -d iank
sudo usermod -a -G postgres iank
if ! out=$(psql -XAtq -Pfieldsep=' ' -vON_ERROR_STOP=on postgres <<<"select 1 from pg_user where usename = 'iank';" 2>/dev/null) || [[ $out != 1 ]]; then
sudo -u postgres createuser -d iank
fi
# initial db creation with:
- # createdb -O iank db_name
+ # createdb -O iank dl
e "vm.hugetlb_shm_group=$(getent group postgres|awk -F : '{print $3}')" | sd /etc/sysctl.d/80-iank-hugepage-postgres.conf
sudo sysctl -p/etc/sysctl.d/80-iank-hugepage-postgres.conf
exit 0
fi
fi
+
+
+
+
read -r _ _ gateway _ ifdev _ <<<"$tmp"
- case $gateway in
- 10.2.0.1)
- dyndomain=b8.nz
- # This domain is for any case where we want some different
- # configuration based on lan vs wan. For right now, the only use
- # is for ssh config to use port forwarding ports on the wan
- # domain.
- dyndomain_internet=i.b8.nz
- ;;
- *)
- return 0
- ;;
- esac
+ if [[ $HOSTNAME == frodo || $gateway == 10.2.0.1 ]]; then
+ dyndomain=b8.nz
+ # This domain is for any case where we want some different
+ # configuration based on lan vs wan. For right now, the only use
+ # is for ssh config to use port forwarding ports on the wan
+ # domain.
+ dyndomain_internet=i.b8.nz
+ else
+ return 0
+ fi
# We check if we are at home by testing gateway ssh
# fingerprint. However, if we found in the past that we are, I dont
printf "%s\n" "$newbytes" >/dev/shm/dynamic-ip-update-state
fi
fi
- if ! $athome && timeout -s 9 5 ssh-keyscan -p 2220 -t rsa $gateway 2>/dev/null | grep -qFx "[$gateway]:2220 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCH+/h1dGEfKEusBblndU2e6QT4wLCm5+yqr/sqh/0X9YfjR7BfWWm8nNmuP55cYc+Wuf5ljB1H1acXEcsl1y8e0j3agHfF0V74FE1N1zz5nn2Ep8NHnmqgEhza38ZxMPh+4p3X7zklEKU7+3SzybKBi8sg0wLzlS2LM0JaUN80zR2sK11Kye3dURUXPk78u5wodOkgcEYRwSYaDMJlUzWP+poRXIDJwFaMQnwmxbl/c84yOyaU0x/d6hFwoRscWecihX+vvBNeSyxR4xr2HDOyUWwJkctyAgt2p7w3tfkXOKcCRzTAjGVIMQLTvo0sG/yJbcyHoEFdFybCsgDvfyYn"; then
- athome=true
- awk '$1 == "'$ifdev':" {print $2 + $10}' /proc/net/dev > /dev/shm/dynamic-ip-update-state
+
+ if ! $athome; then
+ if [[ $HOSTNAME == frodo ]] || timeout -s 9 5 ssh-keyscan -t ed25519 $gateway 2>/dev/null | grep -qFx "$gateway ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIHggN4OjyqJCF5lmqMEBmFAyTFvNruZgNqxj0a9ztls"; then
+ athome=true
+ awk '$1 == "'$ifdev':" {print $2 + $10}' /proc/net/dev > /dev/shm/dynamic-ip-update-state
+ fi
fi
--- /dev/null
+{ "default-address-pools": [ { "base": "172.31.0.0/20", "size": 24 } ] }
--- /dev/null
+#!/bin/bash
+# I, Ian Kelling, follow the GNU license recommendations at
+# https://www.gnu.org/licenses/license-recommendations.en.html. They
+# recommend that small programs, < 300 lines, be licensed under the
+# Apache License 2.0. This file contains or is part of one or more small
+# programs. If a small program grows beyond 300 lines, I plan to change
+# to a recommended GPL license.
+
+# Copyright 2025 Ian Kelling
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+
+# http://www.apache.org/licenses/LICENSE-2.0
+
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# for saving files outside of /etc with etckeeper
+
+rsync -a --relative --mkpath /var/lib/exim4/config.autogenerated /etc/etckeeper/fsmirror/
# I also set this in
# /a/c/filesystem/etc/systemd/system.conf.d/tz.conf
# https://blog.packagecloud.io/eng/2017/02/21/set-environment-variable-save-thousands-of-system-calls/
-export TZ=:/etc/localtime
+# # However, those instructions backfired because emacs erc didn't understand the value
+# export TZ=:/etc/localtime
# ubuntu starts gpg agent automatically with /etc/X11/Xsession.d/90gpg-agent.
# fedora doesn't, which left me to figure this out, and google was no help.
[Manager]
-DefaultEnvironment=TZ=:/etc/localtime
+# see /b/ds/filesystem/etc/profile.d/environment.sh
+#DefaultEnvironment=TZ=:/etc/localtime
# also set in profile.d/environment.sh with explanation there
--- /dev/null
+#!/bin/bash
+# I, Ian Kelling, follow the GNU license recommendations at
+# https://www.gnu.org/licenses/license-recommendations.en.html. They
+# recommend that small programs, < 300 lines, be licensed under the
+# Apache License 2.0. This file contains or is part of one or more small
+# programs. If a small program grows beyond 300 lines, I plan to change
+# to a recommended GPL license.
+
+# Copyright 2025 Ian Kelling
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+
+# http://www.apache.org/licenses/LICENSE-2.0
+
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -eE -o pipefail
+trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" returned $?" >&2' ERR
+
+if [[ $EUID != 0 ]]; then
+ echo "$0: error: expected to be root."
+ exit 1
+fi
+
+
+rule="POSTROUTING -s 10.0.0.0/16 -o eth1 -j MASQUERADE"
+
+if ! iptables -t nat -C $rule &>/dev/null; then
+ iptables -t nat -I $rule
+fi
i3-msg "workspace 4"
# start emacs daemon for profanity/znc if it doesnt exist.
-id=$(i3-msg -t get_tree | jq -e '.. | select(.name?) | select(.name | test("^iznc ")).id')
+id=$(i3-msg -t get_tree | jq -e '.. | select(.name?) | select(.name | test("^e-profanity ")).id')
if [[ ! $id ]]; then
emacsclient -s profanity -nc &>/dev/null
--- /dev/null
+#!/bin/bash
+
+# usage: [-v] -d|-m PID|PGREP_FULL_REGEX...
+#
+# -d Set pids to default priority.
+# -m Set pids to max priority.
+#
+# -v = verbose output.
+
+[[ $EUID == 0 ]] || exec sudo "${BASH_SOURCE[0]}" "$@"
+
+
+. /a/c/fsf-script-lib
+
+maxpri() {
+ for pid; do
+ chrt --all-tasks --rr --reset-on-fork --pid 50 $pid
+ done
+ # we try process group (-g, -P) to hit related processes. If this fails, fall back to pid: (-p, -p)
+ if ! renice -20 -g "$@"; then
+ renice -20 -p "$@"
+ # c1 = realtime, it can starve other processes, which is probably
+ # not something I'd probably want.
+ ionice -c2 -n0 -p "$@"
+ return 0
+ fi
+ ionice -c2 -n0 -P "$@"
+}
+
+
+midpri() {
+ local pid
+ local -a tids
+ for pid; do
+ chrt --all-tasks --other --pid 0 $pid
+ for task in /proc/$pid/task/*; do
+ tids+=("${task##*/}")
+ done
+ done
+ renice -n 0 -p "${tids[@]}"
+ ionice -c 0 -p "${tids[@]}"
+}
+
+#verbose=false
+if [[ $1 == -v ]]; then
+ set -x
+ #verbose=true
+ shift
+fi
+
+
+if [[ $1 == -m ]]; then
+ max=true
+elif [[ $1 == -d ]]; then
+ max=false
+else
+ err "invalid 1st cli arg"
+ exit 1
+fi
+shift
+
+maxpids=()
+midpids=()
+
+while [[ $1 ]]; do
+ unset pids # not needed, just for clarity.
+ if [[ $1 == -m ]]; then
+ max=true
+ elif [[ $1 == -d ]]; then
+ max=false
+ else
+ if [[ $1 =~ $uint_regex ]]; then
+ pids=$1
+ else
+ pids=$(pgrep -d ' ' -f "$1")
+ fi
+ if $max; then
+ maxpids+=( $pids )
+ else
+ midpids+=( $pids )
+ fi
+ fi
+ shift
+done
+
+if (( ${#maxpids[@]} )); then
+ maxpri ${maxpids[@]}
+fi
+
+if (( ${#midpids[@]} )); then
+ midpri ${midpids[@]}
+fi
low_level=70
set-bright() {
- ddcutil --display 1 setvcp 10 $1
+ # loop using proper detection
+ #for dnum in ${displays[@]}; do
+ #
+ for (( dnum=display_count; dnum >= 1; dnum-- )); do
+ # note: I tried running this in the background, but it turns out a 2nd call in parallel
+ # breaks the 1st call.
+ ddcutil --display $dnum setvcp 10 $1
+ done
echo $1 >$state_f
}
+# proper detection, but slow, like .75 seconds.
+#displays=( $(ddcutil detect -t| sed -rn 's/^Display[[:space:]]+([0-9]+)[[:space:]]*$/\1/p' | tac) )
+# instead:
+declare -i display_count
+display_count=$(xrandr | awk '$2 == "connected" {count++} END {print count}')
+
if [[ -s $state_f ]]; then
cur_bright=$(cat $state_f)
# echo "state_f: $cur_bright" # debug
mapper-dev devx
fi
d devx=$devx
- root_dir=$(sed -rn "s,^\s*$devx\s+(\S+).*\bsubvolid=[05]\b.*,\1,p" /etc/mtab /etc/fstab|head -n1)
+ # note: we could also test for "subvol=/", but no need.
+ root_dir=$(awk '$1 == "'"$devx"'" && $3 == "btrfs" && ( $4 !~ /subvol=/ || $4 ~ /subvolid=[05](,|$)/ ) {print $2}' /etc/mtab /etc/fstab|head -n1)
if [[ $root_dir ]]; then
d root_dir=$root_dir
break
if [[ $line ]] && ! i3-check-profanity &>/dev/null; then
dunstify -h string:x-dunst-stack-tag:profanity -- "$line"
fi
+ sleep 1
}
pre="^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]{6}-[0-9]{2} -"
+declare -i ret
while true; do
midnight=$(date -d '00:00:00 tomorrow' +%s)
log_today=$(date '+%Y_%m_%d' "${dev_date[@]}").log
tail-cmd | while true; do
if (( EPOCHSECONDS > midnight + 3 )); then break; fi
- read -t 15 -r l 2>/dev/null || continue
+ ret=0; read -t 15 -r l 2>/dev/null || ret=$?
+ # eg false|read
+ if (( ret == 1 )); then break; fi
+ # timeout
+ if (( ret == 142 )); then
+ continue
+ fi
notify-cmd "$l"
- done
+ done ||:
sleep 2
done
systemctl enable --now ssh-agent-root
fi
+if [[ -d /usr/share/doc/dropbear-initramfs ]]; then
# note: i previously had $auth_dir/root/.ssh/authorized_keys
# but /usr/share/doc/dropbear-initramfs/README.initramfs
cp -p /root/.ssh/authorized_keys $auth_file
update-initramfs -u -k all
fi
+fi
if [[ -e /p/c/subdir_files/.dsh ]]; then
rsync -tpur /p/c/subdir_files/.dsh /root
e finished restoring old host as primary, now exiting $ret due to earlier failed btrbk of /o.
exit $ret
fi
-_s=$(stty size); c=${_s#* }; while ((c-- >0)); do printf $; done; echo
+echo '$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$'
# new system is usable at this point
# once I accidentally accepted incoming mail on old host. I used this script to copy over that mail:
#!/bin/bash
-# Copyright (C) 2023 Free Software Foundation <sysadmin@fsf.org>
-#
-# Note: the FSF recommends copyleft licensing for programs > 300 lines, see
-# https://www.gnu.org/licenses/license-recommendations.en.html.
-#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# block.
set -e
if [[ -s /usr/local/lib/bash-bear ]]; then
+ # shellcheck disable=SC1091
. /usr/local/lib/bash-bear
elif [[ -s /usr/local/lib/err ]]; then
# old name
# shellcheck disable=SC1091
. /usr/local/lib/err
+elif [[ -s ${BASH_SOURCE[0]%/*}/bash-bear ]]; then
+ # shellcheck disable=SC1091 # checking script dir.
+ . ${BASH_SOURCE[0]%/*}/bash-bear
elif [[ $- != *i* ]]; then
# error if this is a script, not an interactive shell.
echo "error: exit 1: missing dependency: /usr/local/lib/bash-bear"
# echo MESSAGE, but use printf so it is safe from options.
e() { printf "%s\n" "$*"; }
+# echo but only when verbose is true.
+ev() {
+ if [[ $verbose == true ]]; then
+ e "$@"
+ fi
+}
+
# usage: ml COMMAND...
#
# Write successful command to log.
# 2025-01-03 03:51:59 main: test message2
err() { echo "$(date "+%F %T") ${FUNCNAME[1]}: $*" >&2; }
-### begin debug-setx related functions ###
-#
-# usage: debug-setx
-#
-# Print executing commands like "set -x", but:
-#
-# - Skips printing many boring/redundant lines. There are related
-# functions below to modify/toggle what gets printed.
-#
-# - Related function h() to prompt before executing printed command.
-#
-# Printing of uninteresting commands can be limited:
-#
-# 1: Do not print command when stack depth is >= debug_max_stack_depth.
-#
-# 2: Allow printing in specific functions with setx-func (see its doc below).
-#
-# There is a hard-coded list of commands to skip or maybe skip. You can
-# improve this.
-#
-debug-setx() {
- local existing_debug_trap
-
- # Note on commands we skip printing:
- # - read ends up being what is shown for 'while read' loops.
-
- # for inheriting debug in subshells
- shopt -s extdebug
-
- debug_prompt=false
- debug_skip=false
- debug_force_print=false
-
- existing_debug_trap=$(trap -p DEBUG 2>&1)
- if [[ $existing_debug_trap && $existing_debug_trap != *_debug-setx-func ]]; then
- trap "$existing_debug_trap; _debug-setx-func" DEBUG
- else
- trap _debug-setx-func DEBUG
- fi
+# Do the equivalent of head on file that might not have line breaks or
+# might be gobblygook. The sed fixes any missing final newline.
+peek() {
+ cat -Ans -- "$1" | head -n20 | head -c1500 | sed a\\ || [[ $? == 141 ]]
}
-# internal function called via debug-setx trap.
-_debug-setx-func() {
- local doprint=false random_delimiter func cmd col debug_cmd
- if [[ $debug_max_stack_depth ]]; then
- funcname_count_max=$(( debug_max_stack_depth + 1 ))
- else
- # within 0 func level, FUNCNAME has 2 in here, eg debug-setx-func main.
- funcname_count_max=99999
- fi
-
- if [[ $BASH_SUBSHELL != [01] ]]; then
- return 0
- fi
-
- if $debug_skip; then
- debug_skip=false
- return 0
- fi
-
- if $debug_prompt; then
- doprint=true
- fi
-
- if $debug_force_print; then
- debug_force_print=false
- doprint=true
- fi
-
- if $debug_print_default; then
-
- ## block for debug_print_funcs
- if ! $doprint; then
- for func in ${debug_print_funcs[@]}; do
- if [[ $func == "${FUNCNAME[1}" ]]; then
- doprint=true
- break
- fi
- done
- fi
-
- ## block for default command & function ignoring
- if ! $doprint && (( ${#FUNCNAME[*]} <= funcname_count_max )); then
- # debug
- #e "${FUNCNAME[*]} ${#FUNCNAME[*]} <= $funcname_count_max"
- case $BASH_COMMAND in
- e\ *|err\ *|echo\ *|printf\ *|read\ *|h|ux|ux\ *)
- : ;;
- for\ *)
- # try to print just the first for loop iteration.
- _debug_setx_cur_for="$BASH_COMMAND ${BASH_LINENO[0]} ${FUNCNAME[1]}"
- if [[ $_debug_setx_cur_for != "$_debug_setx_last_for" ]]; then
- doprint=true
- fi
- _debug_setx_last_for="$_debug_setx_cur_for"
- ;;
- *)
- doprint=true
- ;;
- esac
- fi
-
- fi
-
- if $doprint; then
- # Expanding $1 will be empty, so skip expansion in that case, and some others.
- #
- # TODO: we should be able to grab $1 from the function tracing facilities.
- #
- # Note, we could split the command up and expand other parts
- # but I'm not going to bother.
- if [[ $BASH_COMMAND != *\$[0-9]* && $BASH_COMMAND != *\`* && $BASH_COMMAND != *\$\(* && $BASH_COMMAND == *\$* ]]; then
- random_delimiter=$RANDOM$RANDOM$RANDOM
- # shellcheck disable=SC1003
- _d="$BASH_COMMAND" _d="${_d//'\\'/SUBfopguensOfRifejmu${random_delimiter}SUB}" _d="${_d//\\[adehHjlnrstT@AuvVwW\!\#\$[\]]/\\&}" _d="${_d//\\D\{*\}/\\&}" _d="${_d//\\[012][0-9][0-9]/\\&}" _d="${_d//\\3[0-6][0-9]/\\&}" _d="${_d//\\37[0-7]/\\&}" _d="${_d//SUBfopguensOfRifejmu${random_delimiter}SUB/'\\\\'}"
- cmd="${_d@P}"
- else
- cmd="$BASH_COMMAND"
- fi
- [[ $COLUMNS ]] || { _s=$(stty size); COLUMNS=${_s#* }; }
- if [[ $COLUMNS == *[0-9]* ]]; then
- # generally fill up 2 rows
- col=$(( COLUMNS * 2 - 20 ))
- else
- col=150
- fi
- if (( ${#cmd} > col )); then
- cmd="$(( ${#cmd} - col)) cut: ${cmd:0:col}"
- fi
- echo "+ $cmd" >&2
- fi
-
- if $debug_prompt; then
- # we can type in commands here to inspect the program state.
- read -r -e -p "DEBUG $ " debug_cmd
- while [[ $debug_cmd ]]; do
- eval $debug_cmd
- read -r -e -p "DEBUG $ " debug_cmd
- done
- debug_prompt=false
- fi
-}
-
-# usage: ux [COMMAND...]
-#
-# disable/unset debug-setx default command printing. Runs COMMAND if
-# given. Command arg exists only because the args would be otherwise
-# unused.
-ux() {
- debug_print_default=false
- if [[ $1 ]]; then "$@"; fi
-}
# usage: h [COMMAND...]
#
#
# note: h = random free letter.
h() {
+ # shellcheck disable=SC2034
+ debug_prompt=true
if [[ $1 ]]; then
- debug_prompt=true
"$@"
- else
- debug_prompt=true
fi
}
exit 1
}
-# usage: u1 [COMMAND...]
-#
-# Disable debug-setx printing just for the next command.
-u1() {
- # we have this strange logic because [[ is a command, easier to not
- # have that be between debug_skip=true and $@ and trigger a debug
- # trap.
- if [[ $1 ]]; then
- debug_skip=true
- "$@"
- else
- debug_skip=true
- fi
-}
-
-# usage: dx [COMMAND...]
-#
-# Undo ux() and reenable debug-setx printing.
-dx() {
- if [[ $1 ]]; then
- debug_print_default=true
- "$@"
- else
- debug_print_default=true
- fi
-}
-
-# usage: d1 [COMMAND...]
-#
-# For just one command, reenable debug-setx printing.
-d1() {
- if [[ $1 ]]; then
- debug_force_print=true
- "$@"
- else
- debug_force_print=true
- fi
-}
-
-
-# usage: setx-func [FUNCTION...]
-#
-# Do debug-setx printing within current function or FUNCTION(s) even
-# when called with function stack size greater than
-# $debug_max_stack_depth.
-setx-func() {
- local new_func new_funcs found existing_func
- if [[ ! -v debug_print_funcs ]]; then
- debug_print_funcs=()
- fi
-
- e "${FUNCNAME[*]}"
- if [[ $1 ]]; then
- new_funcs="$*"
- else
- new_funcs="${FUNCNAME[0]}"
- fi
- for new_func in $new_funcs; do
- found=false
- for existing_func in ${debug_print_funcs[@]}; do
- if [[ $existing_func == "$new_func" ]]; then
- found=true
- break
- fi
- done
- if $found; then
- break
- fi
- debug_print_funcs+=($new_func)
- done
-}
-
-### end debug-setx related functions ###
-
-## begin debug-setx background / development notes
-#
-# I often end up writing little 5-10 line scripts. To log what they are doing,
-# I was annoyed with the available options. #1 There is set -x, which usually ends up
-# being > 50% useless lines, very anoying. #2
-# m() { printf "%s\n" "$*";
-#"$@"; } that annoyingly conflicts with command
-# redirected output, and I constantly forget to add it.
-#
-# Better option: debug trap, where we can print $BASH_COMMAND. The main
-# annoying thing about this is that $BASH_COMMAND doesn't have expanded
-# variables.
-#
-# options to expand variables in a $BASH_COMMAND:
-#
-# 1. get bash to do readline's shell-expand-line. I know a hacky way
-# with read, but it wasn't reliable when I tried it in a
-# prompt_command. I could probably create a c program that uses readline
-# to do it pretty easily
-#
-# 2. Use the prompt expansion features @P, but first escape the special
-# prompt characters if there are any. This was the option I went
-# with. It has a small flaw that I realized without calling a regex
-# substitution program, my escaping is not perfect: I temporarily insert
-# a long random string to identify "\\", but it is possible this string
-# could exist in the command and then I would improperly replace
-# it. However, my use case is simply viewing commands I intend to run
-# and I don't see any reason I would intend to run a command with that
-# or that even if I did, it would cause any serious problem to have it
-# be incorrectly displayed.
-#
-# NOTE: One imperfection with both of these, is that we don't want to
-# expand $() or ``, so I look for those chars and then avoid doing it. I
-# think the only way to avoid this would be to modify bash itself in
-# order to do shell-expand-line and then use the result, just as if you
-# pressed the key for it.
-#
-# \\ -> \\\\ : creates problem matching eg: \e
-#
-# alternate:
-#
-# \134 -> RANDOM_LONG_STRING
-#
-# \\ -> \134\134 : creates problem matching \134, we need to match \134!(\134), solved by the RANDOM_LONG_STRING
-#
-# \a -> \134a
-#
-# \D{*} and \123 -> \\&
-#
-# RANDOM_LONG_STRING -> \\134
-#
-# alternate, best:
-#
-# \\ -> RANDOM_LONG_STRING
-#
-# \a -> \\a
-#
-# \D{*} and \123 -> \\&
-#
-# RANDOM_LONG_STRING -> \\\\
-#
-# # incrementally built up test cases, where the output is expected to be the same as the initial _d
-#
-# _d='ok\\\\jyes'; _d="${_d//'\\'/SUBfopguensOfRifejmuSUB}" _d="${_d//\\[adehHjlnrstT@AuvVwW\!\#\$[\]]/\\&}" _d="${_d//SUBfopguensOfRifejmuSUB/'\\\\'}"; e "$_d + ${_d@P}"
-#
-# _d='ok\D{z_ds}yes'; _d="${_d//'\\'/SUBfopguensOfRifejmuSUB}" _d="${_d//\\[adehHjlnrstT@AuvVwW\!\#\$[\]]/\\&}" _d="${_d//\\D\{*\}/\\&}" _d="${_d//SUBfopguensOfRifejmuSUB/'\\\\'}"; e "$_d + ${_d@P}"
-#
-# _d='ok\144ye\134s'; _d="${_d//'\\'/SUBfopguensOfRifejmuSUB}" _d="${_d//\\[adehHjlnrstT@AuvVwW\!\#\$[\]]/\\&}" _d="${_d//\\D\{*\}/\\&}" _d="${_d//\\[012][0-9][0-9]/\\&}" _d="${_d//\\3[0-6][0-9]/\\&}" _d="${_d//\\37[0-7]/\\&}" _d="${_d//SUBfopguensOfRifejmuSUB/'\\\\'}"; e "$_d + ${_d@P}"
-#
-#
-# random interesting script:
-# x=4
-# echo "\$x ${BASH_COMMAND@P}"
-# Warning: Program '/bin/bash' crashed.
-#
-## end debug-setx background / development notes
fi
if [[ $server == none ]]; then
- server=
+ server=server
else
args+=" -s$server"
fi
-# by default, new workspaces are created on whatever screen doesn't have
-# one active or else the current one. That is annoying, I have one
-# primary monitor, I don't want a new workspace created on secondary
-# monitor just because I happen be focused on it. This fixes that.
-workspace 1 output primary
-workspace 2 output MON-LEFT
-workspace 3 output MON-RIGHT
-workspace 4 output MON-RIGHT
-workspace 5 output MON-RIGHT
-workspace 6 output MON-RIGHT
-workspace 7 output MON-RIGHT
-workspace 8 output MON-RIGHT
-workspace 9 output MON-RIGHT
-workspace 10 output MON-RIGHT
+
# todo: this is probably preferable on an x200. Makes the default layout be splitv instead of splith.
#default_orientation vertical
+
# bar is needed for kde connect
bar {
+# conditionally set in myx
+#mode hide
+#hidden_state hide
+
# keep it only on secondary monitor to save space and make for less
# missing pixes in obs live stream. For docs on this, search "output
# primary" in the i3 guide.
bindsym $mod+backslash $ex "scrot"
bindsym $mod+t $ex "i3-set-layout splitv"
+## but this is set dynamically by myx
+bindsym $mod+Shift+t "move workspace to output next"
+
bindsym $mod+g $ex "i3-set-layout tabbed"
bindsym $mod+Shift+9 move container to workspace 10
bindsym $mod+9 workspace 10
+# by default, new workspaces are created on whatever screen doesn't have
+# one active or else the current one. That is annoying, I have one
+# primary monitor, I don't want a new workspace created on secondary
+# monitor just because I happen be focused on it. This fixes that.
+
+workspace 1 output primary
+workspace 2 output primary
+workspace 3 output primary
+workspace 4 output primary
+workspace 5 output primary
+workspace 6 output primary
+workspace 7 output primary
+workspace 8 output primary
+workspace 9 output primary
+workspace 10 output primary
+
+
bindsym $mod+m $ex "dunstctl close-all"
bindsym $mod+Shift+m border toggle
client.focused #4c7899 #285577 #ffffff #2e9ef4 #ff4400
client.focused_inactive #333333 #5f676a #ffffff #484e50 #B8C8CD
client.unfocused #333333 #222222 #888888 #292d2e #B8C8CD
-
# https://wiki.archlinux.org/title/ICC_profiles said it was less
# compatible, so I didn't bother.
+
+# I got a viewsonic and found its color to be noticably different
+# than the dell, so recalibrated. However, I've realized that to
+# generate a better icc profile, I should extract some data from the
+# windows software to calibrate my specific device, and to compare
+# the icc profile it generates with displaycal, and to read the
+# displaycal manual and test some things. Until then, I'm happy to
+# just rely on osd settings that make the monitors look good and
+# similar in a test video showing lots of skin tones.
+
+
+exit 0
+
case $HOSTNAME in
frodo)
- /usr/bin/dispwin -v -d1 -c -I '/a/bin/ds/icc/U3225QE #1 2025-07-29 01-57 D6500 2.2 F-S XYZLUT+MTX.icc'
+
+# /usr/bin/dispwin -v -d1 -c -I '/a/bin/ds/icc/U3225QE #1 2025-07-29 01-57 D6500 2.2 F-S XYZLUT+MTX.icc'
+# /usr/bin/dispwin -v -d1 -c -I '/a/bin/ds/icc/U3225QE #1 2026-09-24 03-06 D6500 S XYZLUT+MTX.icc'
# test that it worked with:
# dispwin -v -d1 -V '/etc/xdgcolor/icc/devices/display/U3225QE #1 2025-07-29 01-57 D6500 2.2 F-S XYZLUT+MTX.icc'
#
# You can also watch the grey color of konsole change slightly when it loads.
+ /usr/bin/dispwin -v -d3 -c -I '/a/bin/ds/icc/VP2488-4K #1 2026-09-24 01-14 D6500 2.2 F-S XYZLUT+MTX.icc'
;;
esac
--- /dev/null
+# Defaults for isc-dhcp-server (sourced by /etc/init.d/isc-dhcp-server)
+
+# Path to dhcpd's config file (default: /etc/dhcp/dhcpd.conf).
+#DHCPDv4_CONF=/etc/dhcp/dhcpd.conf
+#DHCPDv6_CONF=/etc/dhcp/dhcpd6.conf
+
+# Path to dhcpd's PID file (default: /var/run/dhcpd.pid).
+#DHCPDv4_PID=/var/run/dhcpd.pid
+#DHCPDv6_PID=/var/run/dhcpd6.pid
+
+# Additional options to start dhcpd with.
+# Don't use options -cf or -pf here; use DHCPD_CONF/ DHCPD_PID instead
+#OPTIONS=""
+
+# On what interfaces should the DHCP server (dhcpd) serve DHCP requests?
+# Separate multiple interfaces with spaces, e.g. "eth0 eth1".
+INTERFACESv4="eth0"
+INTERFACESv6=""
--- /dev/null
+# dhcpd.conf
+#
+# Sample configuration file for ISC dhcpd
+#
+# Attention: If /etc/ltsp/dhcpd.conf exists, that will be used as
+# configuration file instead of this file.
+#
+
+# option definitions common to all supported networks...
+option domain-name "example.org";
+option domain-name-servers ns1.example.org, ns2.example.org;
+
+default-lease-time 600;
+max-lease-time 7200;
+
+# The ddns-updates-style parameter controls whether or not the server will
+# attempt to do a DNS update when a lease is confirmed. We default to the
+# behavior of the version 2 packages ('none', since DHCP v2 didn't
+# have support for DDNS.)
+ddns-update-style none;
+
+# If this DHCP server is the official DHCP server for the local
+# network, the authoritative directive should be uncommented.
+#authoritative;
+
+# Use this to send dhcp log messages to a different log file (you also
+# have to hack syslog.conf to complete the redirection).
+#log-facility local7;
+
+# No service will be given on this subnet, but declaring it helps the
+# DHCP server to understand the network topology.
+
+#subnet 10.152.187.0 netmask 255.255.255.0 {
+#}
+
+# This is a very basic subnet declaration.
+
+#subnet 10.254.239.0 netmask 255.255.255.224 {
+# range 10.254.239.10 10.254.239.20;
+# option routers rtr-239-0-1.example.org, rtr-239-0-2.example.org;
+#}
+
+# This declaration allows BOOTP clients to get dynamic addresses,
+# which we don't really recommend.
+
+#subnet 10.254.239.32 netmask 255.255.255.224 {
+# range dynamic-bootp 10.254.239.40 10.254.239.60;
+# option broadcast-address 10.254.239.31;
+# option routers rtr-239-32-1.example.org;
+#}
+
+# A slightly different configuration for an internal subnet.
+#subnet 10.5.5.0 netmask 255.255.255.224 {
+# range 10.5.5.26 10.5.5.30;
+# option domain-name-servers ns1.internal.example.org;
+# option domain-name "internal.example.org";
+# option subnet-mask 255.255.255.224;
+# option routers 10.5.5.1;
+# option broadcast-address 10.5.5.31;
+# default-lease-time 600;
+# max-lease-time 7200;
+#}
+
+# Hosts which require special configuration options can be listed in
+# host statements. If no address is specified, the address will be
+# allocated dynamically (if possible), but the host-specific information
+# will still come from the host declaration.
+
+#host passacaglia {
+# hardware ethernet 0:0:c0:5d:bd:95;
+# filename "vmunix.passacaglia";
+# server-name "toccata.example.com";
+#}
+
+# Fixed IP addresses can also be specified for hosts. These addresses
+# should not also be listed as being available for dynamic assignment.
+# Hosts for which fixed IP addresses have been specified can boot using
+# BOOTP or DHCP. Hosts for which no fixed address is specified can only
+# be booted with DHCP, unless there is an address range on the subnet
+# to which a BOOTP client is connected which has the dynamic-bootp flag
+# set.
+#host fantasia {
+# hardware ethernet 08:00:07:26:c0:a5;
+# fixed-address fantasia.example.com;
+#}
+
+# You can declare a class of clients and then do address allocation
+# based on that. The example below shows a case where all clients
+# in a certain class get addresses on the 10.17.224/24 subnet, and all
+# other clients get addresses on the 10.0.29/24 subnet.
+
+#class "foo" {
+# match if substring (option vendor-class-identifier, 0, 4) = "SUNW";
+#}
+
+#shared-network 224-29 {
+# subnet 10.17.224.0 netmask 255.255.255.0 {
+# option routers rtr-224.example.org;
+# }
+# subnet 10.0.29.0 netmask 255.255.255.0 {
+# option routers rtr-29.example.org;
+# }
+# pool {
+# allow members of "foo";
+# range 10.17.224.10 10.17.224.250;
+# }
+# pool {
+# deny members of "foo";
+# range 10.0.29.10 10.0.29.230;
+# }
+#}
+++ /dev/null
-## example of 2 independent networks:
-
-# # top port
-# auto eth2
-# iface eth2 inet static
-# address 10.3.0.4/24
-
-# # bottom port
-# auto eth1
-# iface eth1 inet static
-# address 10.9.0.4/24
-
-
-## manual bond configuration example:
-# modprobe bonding
-# echo +bond0 > /sys/class/net/bonding_masters
-# echo +eth2 > /sys/class/net/bond0/bonding/slaves
-# echo +eth1 > /sys/class/net/bond0/bonding/slaves
-# ip addr add 10.3.0.4/24 dev bond0
-# ip link set bond0 up
-
-## things not needed for us, but could be useful elsewhere:
-
-# Set MII monitoring interval to 100ms for link detection
-#echo 100 > /sys/class/net/bond0/bonding/miimon
-
-## bonding mode (we happen to be using the default)
-#ip link set bond0 down
-#echo balance-rr > /sys/class/net/bond0/bonding/mode
-
-# Also, set slaves to down before adding them.
-
-# status lookup:
-# cat /proc/net/bonding/bond0
-# cat /sys/class/net/bond0/bonding/slaves
-# cat /sys/class/net/bonding_masters
-
-
-auto eth1
-iface eth1 inet static
-address 10.3.0.4/24
--- /dev/null
+[Unit]
+Description=Setup of frodo routing rules
+After=network.target
+Wants=network.target
+StartLimitIntervalSec=0
+
+[Service]
+Type=oneshot
+RemainAfterExit=true
+ExecStart=/usr/local/bin/frodo-route
+
+[Install]
+WantedBy=multi-user.target
[Service]
Type=oneshot
-ExecStart=/usr/bin/flock -w 20 /tmp/newns.flock /usr/local/bin/newns -n 10.174.34 start %i
+ExecStart=/usr/bin/flock -w 20 /tmp/newns.flock /usr/local/bin/newns -n 10.174.1 start %i
ExecStop=/usr/bin/flock -w 20 /tmp/newns.flock /usr/local/bin/newns stop %i
RemainAfterExit=yes
Type=simple
ExecReload=/bin/bash -c 'exec /usr/bin/wg syncconf %i <(exec /usr/bin/wg-quick strip %i)'
ExecStartPre=/sbin/iptables-restore /a/bin/distro-setup/transmission-firewall/netns.rules
-ExecStartPre=/usr/sbin/ip r add 10.8.0.0/24 via 10.174.34.1 dev veth1-client
+ExecStartPre=/usr/sbin/ip r add 10.8.0.0/24 via 10.174.1.1 dev veth1-client
ExecStartPre=/usr/bin/wg-quick up %i
ExecStart=/bin/sleep infinity
ExecStopPost=/usr/bin/wg-quick down %i
-ExecStopPost=/usr/sbin/ip r del 10.8.0.0/24 via 10.174.34.1 dev veth1-client
+ExecStopPost=/usr/sbin/ip r del 10.8.0.0/24 via 10.174.1.1 dev veth1-client
NetworkNamespacePath=/var/run/netns/%i
BindReadOnlyPaths=/etc/tr-resolv:/run/systemd/resolve:norbind /etc/basic-nsswitch:/etc/resolved-nsswitch:norbind
# copied from wg-quick@.service
+++ /dev/null
-
-## example of 2 independent networks:
-
-# # top right port
-# auto eth0
-# iface eth0 inet static
-# address 10.3.0.2/24
-
-# # bottom left port
-# auto eth2
-# iface eth2 inet static
-# address 10.9.0.2/24
-# #
-
-
-auto eth0
-iface eth0 inet static
-address 10.3.0.2/24
-#
-ifconfig-push 10.5.5.34 255.255.255.0
+ifconfig-push 10.5.5.1 255.255.255.0
# SPDX-License-Identifier: GPL-3.0-or-later
-# TODO: track the actual generated exim config files in git. Somehow an
-# exim update screwed up the config file, probably by generating it
-# outside of the normal processes. It was fixed when I reran this file,
-# but then I didn't actually know for sure what went wrong.
+# TODO: on desktop, somehow
+# exim updates screwed up the config file, probably by generating it
+# outside of the normal processes. I'm tracking those changes via
+# copies to
+# /etc/etckeeper/fsmirror/var/lib/exim4/config.autogenerated
+# which is done via the script:
+# /a/c/filesystem/etc/etckeeper/commit.d/20iank-mirror. use that
+# to figure out a solution
+#
# todo:
# on bk (and fsf servers that run multiple exim4 daemons, eg eximfsf2 and eximfsf3),
for service; do
enabled=$(systemctl is-enabled $service 2>/dev/null ||:)
if [[ $enabled != enabled ]]; then
- m systemctl enable $service
+ m systemctl --now enable $service
+ continue
+ fi
+ if ! systemctl --quiet is-active $service; then
+ m systemctl start $service
fi
- m systemctl start $service
done
}
mailhost() {
# installs epanicclean iptables-exim ip6tables-exim
/a/bin/ds/install-my-scripts
-if [[ $(debian-codename-compat) == bionic ]]; then
- cat >/etc/apt/preferences.d/spamassassin <<'EOF'
-Package: spamassassin sa-compile spamc
-Pin: release n=focal,o=Ubuntu
-Pin-Priority: 500
-EOF
-fi
-
unit-exists() {
systemctl cat $1 &>/dev/null
# bad packages that sometimes get automatically installed
pu openresolv resolvconf
-soff openvpn
-
-
-if [[ $(debian-codename) == etiona ]]; then
- # ip6tables stopped loading on boot. openvpn has reduced capability set,
- # so running iptables as part of openvpn startup wont work. This should do it.
- pi iptables-persistent
- cat >/etc/iptables/rules.v6 <<'EOF'
-*mangle
-COMMIT
-*nat
-COMMIT
-EOF
- # load it now.
- m ip6tables -S >/dev/null
-fi
-
-# our nostart pi fails to avoid enabling
-
-
# * initial dns config & daemon setup
#
# old file. remove when all hosts updated, 2023-09-11
rm -fv /etc/exim4/conf.d/clamav_data_acl
+if ! groups clamav | grep -q Debian-exim; then
+ m usermod -a -G Debian-exim clamav
+fi
+
pi-nostart clamav
-m usermod -a -G Debian-exim clamav
u /etc/systemd/system/clamav-daemon.service.d/fix.conf <<EOF
[Service]
;;&
$MAIL_HOST)
test_froms=(ian@iankelling.org z@zroe.org iank@gnu.org)
- test_tos=(testignore@je.b8.nz testignore@amnimal.ninja jtuttle@gnu.org)
+ test_tos=(testignore@amnimal.ninja jtuttle@gnu.org)
cat >>/etc/cron.d/mailtest <<EOF
# 10 am friday
;;&
bk)
test_froms=(testignore@amnimal.ninja)
- test_tos=(testignore@iankelling.org testignore@je.b8.nz)
+ test_tos=(testignore@iankelling.org)
# We dont need to send from different addresses to the same
# address. this breaks down our nice elegant logic of building up
# froms and tos , so I just handle amnimal.ninja in a special case
BAYES_00|BODY_SINGLE_WORD|FROM_FMBLA_NEWDOM*|autolearn) : ;;
# These have somewhat randomly been added and removed, resulting in useless alerts, so ignore them.
- RCVD_IN_DNSWL_MED|DKIMWL_WL_HIGH) : ;;
+ RCVD_IN_DNSWL_MED|DKIMWL_WL_HIGH|RCVD_IN_DNSWL_LOW) : ;;
SPF_HELO_NEUTRAL)
# some of my domains use neutral spf, treat them the same.
case $HOSTNAME in
bk)
folders=(/m/md/amnimal.ninja/testignore)
- froms=(ian@iankelling.org z@zroe.org testignore@je.b8.nz iank@gnu.org)
+ froms=(ian@iankelling.org z@zroe.org iank@gnu.org)
;;
je)
froms=(ian@iankelling.org z@zroe.org iank@gnu.org testignore@amnimal.ninja)
*)
folders=(/m/md/l/testignore)
# save some cpu cycles
- froms=(testignore@je.b8.nz testignore@amnimal.ninja ian@iankelling.org z@zroe.org)
+ froms=(testignore@amnimal.ninja ian@iankelling.org z@zroe.org)
if ! $int; then
### begin rsyncing fencepost email ###
# We dont want to exit if rsync fails, that will get caught by
cat <<EOF
Usage: $script_name [OPTIONS]
-Turns on/off secondary monitor.
-
-Sets resolution.
-
-Alters i3 config.
+Alters i3 config depending on host & a few other things.
note: I used to run it in ~/.xsession, but then I made it sudo which
doesn't work with that.
--n Dry run
-
--f No split, full resolution, like the screen would be without any
- modifications. This happens automatically for small screens.
+note: sometimes windows end up on workspaces that we don't have keybinds
+to switch to, like 12. I don't yet know a good solution, but some useful
+commands:
--r Restart secondary monitor
-
--s split type. split monitor into 1 or more virtual screens
- full (default): no split, full screen.
- tall: half screen.
- quarter: left side is 2 quarter screens, right is 1 tall screen
+i3-msg -t get_workspaces
+i3-msg workspace 11
+i3-msg workspace 12
i3-msg "$@"
fi
}
-xmod() {
- xrandr "$@"
- gen_arg=-r
-}
date "+%A, %B %d, %r, %S seconds"
-dry_run=false
-downres=false
-quarter=false
-tall=false
-restart=false
-
-
-xf=$(mktemp)
-xrandr >$xf
m() {
if $dry_run; then
fi
}
-
-
-primary_info=$(awk '$2 == "connected" && $3 == "primary" {print $1,$4}' $xf)
-
-secondary_out=$(awk '$2 == "connected" && $3 != "primary" {print $1}' $xf)
-# Some systems only have a non-primary connected.
-if [[ ! $primary_info ]]; then
- primary_info=$(awk '$2 == "connected" {print $1,$3}' $xf)
- xrandr --output $secondary_out --primary
- secondary_out=
-fi
-
-# res_info eg: 3840x2160+1920+0
-read -r primary_out primary_res_info <<<"$primary_info"
-
-primary_res=${primary_res_info%%+*}
-primary_x=${primary_res%x*}
-primary_y=${primary_res#*x}
-
-if [[ $secondary_out ]]; then
-
- x_offset=$primary_x
- left_right_arg=--right-of
-
- # dp-1 moves from left to right sometimes, i just move it out of the
- # conditional and comment it as needed.
-
- winchair=false
- if edid-test 192efbdcef; then
- winchair=true
- fi
-
- if $winchair; then
- left_right_arg=--left-of
- x_offset=0
- fi
-
-
- # its a small monitor, so I run:
- # startx -- -dpi 120
- #
- # And x decides the primary display should have non-full
- # resolution. This is a quick hopefully temporary fix.
- if $winchair; then
- xrandr --output eDP-1 --mode 1920x1200
- fi
-
-
- left_right_arg="$left_right_arg $primary_out"
-
- target_out=$secondary_out
- target_res=$(grep -A1 -E "^$secondary_out " $xf | tail -n1 | awk '{print $1}')
- target_x=${target_res%x*}
- target_y=${target_res#*x}
-else
- target_out=$primary_out
- x_offset=0
- target_res=$primary_res
- target_x=$primary_x
- target_y=$primary_y
-fi
-
-
-if (( target_x <= 1280 )); then
- quarter=false
- tall=false
-elif (( target_x <= 1920 )); then
- quarter=false
- tall=true
-fi
-
-
##### begin command line parsing ########
-temp=$(getopt -l help fnrs: "$@") || usage 1
+temp=$(getopt -l help h "$@") || usage 1
eval set -- "$temp"
while true; do
case $1 in
- -f)
- downres=false
- quarter=false
- tall=false
- ;;
- -n) dry_run=true ;;
- -s)
- case $2 in
- tall)
- tall=true
- quarter=false
- ;;
- quarter)
- tall=false
- quarter=true
- ;;
- full)
- tall=false
- quarter=false
- ;;
- esac
- shift
- ;;
- -r) restart=true ;;
-h|--help) usage 0 ;;
--) shift; break ;;
*) echo "$0: Internal error! unexpected args: $*" ; exit 1 ;;
##### end command line parsing ########
-if $downres && (( target_x > 2560 )); then
- target_x=2560
- target_y=1440
- target_res=${target_x}x$target_y
+if [[ $HOSTNAME == frodo ]]; then
+ # saved arandr command
+ xrandr --output HDMI-0 --mode 3840x2160 --pos 11520x0 --rotate normal --output DP-0 --primary --mode 3840x2160 --pos 0x0 --rotate normal --output DP-1 --off --output DP-2 --mode 3840x2160 --pos 3840x0 --rotate normal --output DP-3 --off --output DP-4 --mode 3840x2160 --pos 7680x0 --rotate normal --output DP-5 --off
fi
-half_x=$(( target_x / 2 ))
-half_y=$(( target_y / 2 ))
-
-
-for mon_suffix in TOP-LEFT BOTTOM-LEFT LEFT RIGHT; do
- if xrandr --listmonitors | awk '$2 == "MON-'$mon_suffix\" |grep . >/dev/null; then
- m xmod --delmonitor MON-$mon_suffix
- fi
-done
-
-if [[ ! $secondary_out ]] || grep -A1 disconnected $xf | grep '^[[:space:]]'; then
- # gets rid of leftover secondary
- if [[ $HOSTNAME != frodo ]]; then
- m xmod --auto
-
- # new monitor on frodo, I've been having to run this to get the full refresh rate:
- # xrandr --output DP-0 --mode 3840x2160 --rate 120
- # testing if this xmod is getting in the way.
- fi
-fi
-
-if [[ $secondary_out ]] && $restart; then
- m xmod --output $secondary_out --off
- m sleep 2
-fi
-
-if [[ $secondary_out || $primary_res != "$target_res" ]]; then
- m xmod --output $target_out $left_right_arg --mode $target_res
-fi
-
-if $tall; then
- # 298 & 336 are millimeters. I took them from a monitor I was using. I
- # don't know if they are important, I assume not important enough to
- # change for different monitors.
- m xmod --setmonitor MON-LEFT $half_x/298x$target_y/336+$x_offset+0 $target_out
- m xmod --setmonitor MON-RIGHT $half_x/298x$target_y/336+$(( x_offset + half_x ))+0 none
-
-elif $quarter; then
- m xmod --setmonitor MON-LEFT $half_x/298x$half_y/336+$x_offset+0 $target_out
- # note: this bottom left is buggy when it comes to context menus,
- # including in web pages. In the tall configuration, I sometimes see
- # them in another "monitor" area, but with this bottom left monitor,
- # they aren't displayed at all, as if the window system is displaying
- # them off screen. When that happens, I just switch to the tall
- # configuration, use the dialog, and them maybe switch back.
- m xmod --setmonitor MON-BOTTOM-LEFT $half_x/298x$half_y/336+$x_offset+$half_y none
- m xmod --setmonitor MON-RIGHT $half_x/298x$target_y/336+$(( x_offset + half_x ))+0 none
-fi
-
-
-## begin i3 config ##
-move_outputs=()
-ws_outputs=()
-if [[ $secondary_out ]]; then
- ws1_output=$primary_out
- move_outputs=($primary_out)
-elif $tall || $quarter; then
- ws1_output=MON-RIGHT
-fi
-
-ws_outputs=(
- $ws1_output
-)
-
-
-if $tall; then
- ws_outputs+=(
- MON-LEFT
- MON-RIGHT
- )
- move_outputs+=(MON-RIGHT)
-elif $quarter; then
- ws_outputs+=(
- MON-LEFT
- MON-BOTTOM-LEFT
- MON-RIGHT
- )
- move_outputs+=(MON-BOTTOM-LEFT MON-RIGHT)
-elif [[ $secondary_out ]]; then
- move_outputs+=($secondary_out)
- ws_outputs+=($secondary_out)
-
-fi
-
-#echo d1 ${ws_outputs[@]}
-
-rm -f ~/i3-myx.conf
-total_ws_count=11
-for (( i=0; i<total_ws_count; i++ )); do
- ws=$(( i+1 ))
- tmp=${ws_outputs[$i]}
- # use the last output in the array for all remaining workspaces
- if [[ $tmp ]]; then
- ws_out=$tmp
- fi
- echo "workspace $ws output $ws_out" >>~/i3-myx.conf
-done
-
{
cat /a/bin/ds/i3-sway/bar.conf
- ## for when we are temporarily running some automation which auto-unhides the bar constantly
- ## and overlaps the bottom of windows, so for now, i'm unconditionally
- ## displaying it. When that is done, remove the below echo and
- ## uncomment the conditional below.
+
+ ## I made this conditional once when running some automation which
+ ## auto-unhides the bar constantly and overlaps the bottom of windows
+ #
#echo "}"
- if [[ $secondary_out ]]; then
- echo "}"
- else
echo 'mode hide
hidden_state hide
}'
- fi
} >> ~/i3-myx.conf
-if (( ${#move_outputs[@]} )); then
- echo "bindsym \$mod+Shift+t move workspace to output ${move_outputs[*]} # set by myx" >>~/i3-myx.conf
-else
- echo "# bindsym \$mod+Shift+t move workspace to output XXX XXX # note: if we had logical X screen or multimons, this would be set by myx" >>~/i3-myx.conf
-fi
# give it some time to reload or adjust to new x settings.
+sleep 1
# i3-msg -t get_outputs | jq -C .
# showed
# This was incorrect. The correct thing is that DP-1 is active, HDMI-2 is not active.
# Restarting i3 did not help.
-sleep 1
-m /a/bin/ds/i3-sway/gen $gen_arg
-
-if (( ${#ws_outputs[@]} )); then
-
- declare -A ws_expected_out
-
- for (( i=0; i<total_ws_count; i++ )); do
- ws=$(( i+1 ))
- tmp=${ws_outputs[$i]}
- # use the last output in the array for all remaining workspaces
- if [[ $tmp ]]; then
- ws_out=$tmp
- fi
- ws_expected_out[$((i + 1))]=$ws_out
- done
-
- # If we move a workspace, it could cause an empty workspace to
- # disappear, and then we need to refresh our list. refresh_count is a
- # sanity check to make sure this doesn't go wrong and cause an
- # infinite loop.
- refresh_count=0
- refresh_workspaces=true
- while $refresh_workspaces; do
- if (( refresh_count > 20 )); then
- cat <<'EOF' >&2
-
-ERROR: moving workspaces is not working as expected I've seen it happen
-that an output should not exist anymore. Restarting i3 fixed it, reloading did not.
-This script did a restart, but it might need a sleep before doing so.
-EOF
- exit 1
- fi
- refresh_count=$(( refresh_count + 1 ))
- refresh_workspaces=false
- tmps=$(i3 -t get_workspaces)
- tmps=$(jq -r '.[] | .num, .output' <<<"$tmps")
- while read -r ws; do
- read -r output || break
- if [[ $ws != [0-9] && $ws != 10 ]]; then
- echo "$0: error: unexpected workspace found: $ws. continuing"
- continue
- fi
- if [[ ${ws_expected_out[$ws]} != "$output" ]]; then
- m i3 '[workspace="'$ws'"]' move workspace to output ${ws_expected_out[$ws]}
- refresh_workspaces=true
- break
- fi
- done <<<"$tmps"
- done
-fi
+m /a/bin/ds/i3-sway/gen
+
## end i3 config ##
echo -n "myx end: "
date "+%A, %B %d, %r, %S seconds"
-
-# myx -f
-# Tuesday, July 23, 05:54:37 PM, 37 seconds
-# myx: xmod --delmonitor MON-LEFT
-# myx: xmod --delmonitor MON-RIGHT
-# myx: xmod --output DP-1 --right-of eDP-1 --mode 3840x2160
-# d1 eDP-1 DP-1
-# myx: /a/bin/ds/i3-sway/gen -r
-# /a/bin/ds/i3-sway/gen: i3-msg restart
-# [{"success":true}]
-# myx: i3 [workspace="2"] move workspace to output DP-1
-# ERROR: No output matched
-# [{"success":false,"error":"No output matched"}]
-# /a/exe/myx:63: `i3-msg "$@"' returned 2
-# from /a/exe/myx:63:in `i3 [workspace="2"] move workspace to output DP-1'
-# from /a/exe/myx:88:in `m i3 [workspace="2"] move workspace to output DP-1'
-# from /a/exe/myx:330:in `main -f'
-# /a/exe/myx: exiting with status 2
--- /dev/null
+#!/bin/bash
+# I, Ian Kelling, follow the GNU license recommendations at
+# https://www.gnu.org/licenses/license-recommendations.en.html. They
+# recommend that small programs, < 300 lines, be licensed under the
+# Apache License 2.0. This file contains or is part of one or more small
+# programs. If a small program grows beyond 300 lines, I plan to change
+# to a recommended GPL license.
+
+# Copyright 2024 Ian Kelling
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+
+# http://www.apache.org/licenses/LICENSE-2.0
+
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -e; . /usr/local/lib/bash-bear; set +e
+
+script_name="${0##*/}"
+usage() {
+ cat <<EOF
+Usage: $script_name [OPTIONS]
+
+Turns on/off secondary monitor.
+
+Sets resolution.
+
+Alters i3 config.
+
+note: I used to run it in ~/.xsession, but then I made it sudo which
+doesn't work with that.
+
+note: sometimes windows end up on workspaces that we don't have keybinds
+to switch to, like 12. I don't yet know a good solution, but some useful
+commands:
+
+i3-msg -t get_workspaces
+i3-msg workspace 11
+i3-msg workspace 12
+
+
+-n Dry run
+
+-f No split, full resolution, like the screen would be without any
+ modifications. This is default.
+
+-r Restart secondary monitor
+
+-s split type. split monitor into 1 or more virtual screens
+ full (default): no split, full screen.
+ tall: half screen.
+ quarter: left side is 2 quarter screens, right is 1 tall screen
+ auto: One of the above depending on screen size.
+
+
+
+-h|--help Print help and exit.
+
+Note: Uses GNU getopt options parsing style
+EOF
+ exit $1
+}
+
+edid-test() {
+ local edid_10_prefix="$1"
+ sha256sum /sys/class/drm/*/edid | grep -Eq ^$edid_10_prefix &>/dev/null || [[ $? == 141 ]]
+}
+
+i3() {
+ if [[ $I3SOCK ]]; then
+ i3-msg "$@"
+ fi
+}
+xmod() {
+ xrandr "$@"
+ gen_arg=-r
+}
+
+date "+%A, %B %d, %r, %S seconds"
+
+
+dry_run=false
+downres=false
+quarter=false
+tall=false
+restart=false
+
+
+xf=$(mktemp)
+xrandr >$xf
+
+m() {
+ if $dry_run; then
+ printf "$script_name: dry run: %s\n" "$*"
+ else
+ printf "$script_name: %s\n" "$*"; "$@"
+ fi
+}
+
+
+
+primary_info=$(awk '$2 == "connected" && $3 == "primary" {print $1,$4}' $xf)
+
+secondary_out=$(awk '$2 == "connected" && $3 != "primary" {print $1}' $xf)
+# Some systems only have a non-primary connected.
+if [[ ! $primary_info ]]; then
+ primary_info=$(awk '$2 == "connected" {print $1,$3}' $xf)
+ xrandr --output $secondary_out --primary
+ secondary_out=
+fi
+
+# res_info eg: 3840x2160+1920+0
+read -r primary_out primary_res_info <<<"$primary_info"
+
+primary_res=${primary_res_info%%+*}
+primary_x=${primary_res%x*}
+primary_y=${primary_res#*x}
+
+if [[ $secondary_out ]]; then
+
+ x_offset=$primary_x
+ left_right_arg=--right-of
+
+ left_right_arg="$left_right_arg $primary_out"
+
+ target_out=$secondary_out
+ target_res=$(grep -A1 -E "^$secondary_out " $xf | tail -n1 | awk '{print $1}')
+ target_x=${target_res%x*}
+ target_y=${target_res#*x}
+else
+ target_out=$primary_out
+ x_offset=0
+ target_res=$primary_res
+ target_x=$primary_x
+ target_y=$primary_y
+fi
+
+tall=false
+quarter=false
+downres=false
+
+
+##### begin command line parsing ########
+
+temp=$(getopt -l help fnrs: "$@") || usage 1
+eval set -- "$temp"
+while true; do
+ case $1 in
+ -f)
+ downres=false
+ quarter=false
+ tall=false
+ ;;
+ -n) dry_run=true ;;
+ -s)
+ case $2 in
+ auto)
+ if (( target_x <= 1280 )); then
+ quarter=false
+ tall=false
+ elif (( target_x <= 1920 )); then
+ quarter=false
+ tall=true
+ fi
+ ;;
+ tall)
+ tall=true
+ quarter=false
+ ;;
+ quarter)
+ tall=false
+ quarter=true
+ ;;
+ full)
+ tall=false
+ quarter=false
+ ;;
+ esac
+ shift
+ ;;
+ -r) restart=true ;;
+ -h|--help) usage 0 ;;
+ --) shift; break ;;
+ *) echo "$0: Internal error! unexpected args: $*" ; exit 1 ;;
+ esac
+ shift
+done
+
+##### end command line parsing ########
+
+
+if $downres && (( target_x > 2560 )); then
+ target_x=2560
+ target_y=1440
+ target_res=${target_x}x$target_y
+fi
+
+
+half_x=$(( target_x / 2 ))
+half_y=$(( target_y / 2 ))
+
+
+for mon_suffix in TOP-LEFT BOTTOM-LEFT LEFT RIGHT; do
+ if xrandr --listmonitors | awk '$2 == "MON-'$mon_suffix\" |grep . >/dev/null; then
+ m xmod --delmonitor MON-$mon_suffix
+ fi
+done
+
+if [[ ! $secondary_out ]] || grep -A1 disconnected $xf | grep '^[[:space:]]'; then
+ # gets rid of leftover secondary
+ if [[ $HOSTNAME != frodo ]]; then
+ m xmod --auto
+
+ # new monitor on frodo, I've been having to run this to get the full refresh rate:
+ # xrandr --output DP-0 --mode 3840x2160 --rate 120
+ # testing if this xmod is getting in the way.
+ fi
+fi
+
+if [[ $secondary_out ]] && $restart; then
+ m xmod --output $secondary_out --off
+ m sleep 2
+fi
+
+if [[ $secondary_out || $primary_res != "$target_res" ]]; then
+ : # todo: update this based on current monitor setup.
+ #m xmod --output $target_out $left_right_arg --mode $target_res
+fi
+
+if $tall; then
+ # 298 & 336 are millimeters. I took them from a monitor I was using. I
+ # don't know if they are important, I assume not important enough to
+ # change for different monitors.
+ m xmod --setmonitor MON-LEFT $half_x/298x$target_y/336+$x_offset+0 $target_out
+ m xmod --setmonitor MON-RIGHT $half_x/298x$target_y/336+$(( x_offset + half_x ))+0 none
+
+elif $quarter; then
+ m xmod --setmonitor MON-LEFT $half_x/298x$half_y/336+$x_offset+0 $target_out
+ # note: this bottom left is buggy when it comes to context menus,
+ # including in web pages. In the tall configuration, I sometimes see
+ # them in another "monitor" area, but with this bottom left monitor,
+ # they aren't displayed at all, as if the window system is displaying
+ # them off screen. When that happens, I just switch to the tall
+ # configuration, use the dialog, and them maybe switch back.
+ m xmod --setmonitor MON-BOTTOM-LEFT $half_x/298x$half_y/336+$x_offset+$half_y none
+ m xmod --setmonitor MON-RIGHT $half_x/298x$target_y/336+$(( x_offset + half_x ))+0 none
+fi
+
+
+## begin i3 config ##
+move_outputs=()
+ws_outputs=()
+if [[ $secondary_out ]]; then
+ ws1_output=$primary_out
+ move_outputs=($primary_out)
+elif $tall || $quarter; then
+ ws1_output=MON-RIGHT
+fi
+
+ws_outputs=(
+ $ws1_output
+)
+
+
+if $tall; then
+ ws_outputs+=(
+ MON-LEFT
+ MON-RIGHT
+ )
+ move_outputs+=(MON-RIGHT)
+elif $quarter; then
+ ws_outputs+=(
+ MON-LEFT
+ MON-BOTTOM-LEFT
+ MON-RIGHT
+ )
+ move_outputs+=(MON-BOTTOM-LEFT MON-RIGHT)
+elif [[ $secondary_out ]]; then
+ move_outputs+=($secondary_out)
+ ws_outputs+=($secondary_out)
+
+fi
+
+#echo d1 ${ws_outputs[@]}
+
+rm -f ~/i3-myx.conf
+total_ws_count=11
+for (( i=0; i<total_ws_count; i++ )); do
+ ws=$(( i+1 ))
+ tmp=${ws_outputs[$i]}
+ # use the last output in the array for all remaining workspaces
+ if [[ $tmp ]]; then
+ ws_out=$tmp
+ fi
+ if [[ $HOSTNAME != frodo ]]; then
+ echo "workspace $ws output $ws_out" >>~/i3-myx.conf
+ fi
+done
+
+{
+ cat /a/bin/ds/i3-sway/bar.conf
+
+ ## for when we are temporarily running some automation which auto-unhides the bar constantly
+ ## and overlaps the bottom of windows, so for now, i'm unconditionally
+ ## displaying it. When that is done, remove the below echo and
+ ## uncomment the conditional below.
+ #echo "}"
+
+ if [[ $secondary_out && $HOSTNAME != frodo ]]; then
+ echo "}"
+ else
+ echo 'mode hide
+hidden_state hide
+}'
+ fi
+
+} >> ~/i3-myx.conf
+
+if (( ${#move_outputs[@]} )); then
+ echo "bindsym \$mod+Shift+t move workspace to output next # set by myx" >>~/i3-myx.conf
+ #echo "bindsym \$mod+Shift+t move workspace to output ${move_outputs[*]} # set by myx" >>~/i3-myx.conf
+else
+ echo "# bindsym \$mod+Shift+t move workspace to output XXX XXX # note: if we had logical X screen or multimons, this would be set by myx" >>~/i3-myx.conf
+fi
+# give it some time to reload or adjust to new x settings.
+
+# i3-msg -t get_outputs | jq -C .
+# showed
+# {
+# "name": "HDMI-2",
+# "active": true,
+# "primary": false,
+# "rect": {
+# "x": 1920,
+# "y": 0,
+# "width": 3840,
+# "height": 2160
+# },
+# "current_workspace": "3"
+# },
+# {
+# "name": "DP-1",
+# "active": false,
+# "primary": false,
+# "rect": {
+# "x": 1920,
+# "y": 0,
+# "width": 3840,
+# "height": 2160
+# },
+# "current_workspace": null
+# }
+# This was incorrect. The correct thing is that DP-1 is active, HDMI-2 is not active.
+# Restarting i3 did not help.
+
+sleep 1
+m /a/bin/ds/i3-sway/gen $gen_arg
+
+if (( ${#ws_outputs[@]} )); then
+
+ declare -A ws_expected_out
+
+ for (( i=0; i<total_ws_count; i++ )); do
+ ws=$(( i+1 ))
+ tmp=${ws_outputs[$i]}
+ # use the last output in the array for all remaining workspaces
+ if [[ $tmp ]]; then
+ ws_out=$tmp
+ fi
+ ws_expected_out[$((i + 1))]=$ws_out
+ done
+
+ # If we move a workspace, it could cause an empty workspace to
+ # disappear, and then we need to refresh our list. refresh_count is a
+ # sanity check to make sure this doesn't go wrong and cause an
+ # infinite loop.
+ refresh_count=0
+ refresh_workspaces=true
+ while $refresh_workspaces; do
+ if (( refresh_count > 20 )); then
+ cat <<'EOF' >&2
+
+ERROR: moving workspaces is not working as expected I've seen it happen
+that an output should not exist anymore. Restarting i3 fixed it, reloading did not.
+This script did a restart, but it might need a sleep before doing so.
+EOF
+ exit 1
+ fi
+ refresh_count=$(( refresh_count + 1 ))
+ refresh_workspaces=false
+ tmps=$(i3 -t get_workspaces)
+ tmps=$(jq -r '.[] | .num, .output' <<<"$tmps")
+ while read -r ws; do
+ read -r output || break
+ if [[ $ws != [0-9] && $ws != 10 ]]; then
+ echo "$0: error: unexpected workspace found: $ws. continuing"
+ continue
+ fi
+ if [[ ${ws_expected_out[$ws]} != "$output" ]]; then
+ m i3 '[workspace="'$ws'"]' move workspace to output ${ws_expected_out[$ws]}
+ refresh_workspaces=true
+ break
+ fi
+ done <<<"$tmps"
+ done
+fi
+## end i3 config ##
+
+
+
+m /a/exe/input-setup
+
+echo -n "myx end: "
+date "+%A, %B %d, %r, %S seconds"
+
+
+# myx -f
+# Tuesday, July 23, 05:54:37 PM, 37 seconds
+# myx: xmod --delmonitor MON-LEFT
+# myx: xmod --delmonitor MON-RIGHT
+# myx: xmod --output DP-1 --right-of eDP-1 --mode 3840x2160
+# d1 eDP-1 DP-1
+# myx: /a/bin/ds/i3-sway/gen -r
+# /a/bin/ds/i3-sway/gen: i3-msg restart
+# [{"success":true}]
+# myx: i3 [workspace="2"] move workspace to output DP-1
+# ERROR: No output matched
+# [{"success":false,"error":"No output matched"}]
+# /a/exe/myx:63: `i3-msg "$@"' returned 2
+# from /a/exe/myx:63:in `i3 [workspace="2"] move workspace to output DP-1'
+# from /a/exe/myx:88:in `m i3 [workspace="2"] move workspace to output DP-1'
+# from /a/exe/myx:330:in `main -f'
+# /a/exe/myx: exiting with status 2
debug-me
debootstrap
debconf-doc
+ dejagnu
devscripts
ddcutil
dillo
fi
fi
-if [[ $HOSTNAME == "$HOST2" ]]; then
- m sudo -u iank XDG_RUNTIME_DIR=/run/user/1000 systemctl --no-block --user enable --now awatch.service ||:
-else
- m sudo -u iank XDG_RUNTIME_DIR=/run/user/1000 systemctl --no-block --user disable --now awatch.service ||:
-fi
+# commented because i'm trying out the status bar that stays hidden until super is
+# pressed, which causes an awatch error. Don't feel like fixing it
+# atm.
+# if [[ $HOSTNAME == "$HOST2" ]]; then
+# m sudo -u iank XDG_RUNTIME_DIR=/run/user/1000 systemctl --no-block --user enable --now awatch.service ||:
+# else
+# m sudo -u iank XDG_RUNTIME_DIR=/run/user/1000 systemctl --no-block --user disable --now awatch.service ||:
+# fi
# todo: whats going on here? figure out if this should be removed.
mtest_found=true
fi
done
- if (( mtest_count < 4 )); then
+ if (( mtest_count < 3 )); then
mtest_found=true
fi
if $mtest_found; then