aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-05-19 18:38:39 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-05-19 18:38:39 +0200
commite8cf42f2f17151378574ee5b50f29904a1067bee (patch)
tree86b4db80971ecf9818ad769bd8b7fa337d218731
parentc3bfa44d1b6da88c184fc3312944cf47d1dfd7f2 (diff)
downloadbin-e8cf42f2f17151378574ee5b50f29904a1067bee.tar.gz
bin-e8cf42f2f17151378574ee5b50f29904a1067bee.zip
added readmeHEADmain
-rw-r--r--.gitignore8
-rw-r--r--README.md2
-rw-r--r--archive/bridge-sync.sh.bak31
-rwxr-xr-xblocks/block-cpu23
-rwxr-xr-xblocks/block-datetime2
-rwxr-xr-xblocks/block-mem2
-rwxr-xr-xblocks/block-net7
-rwxr-xr-xblocks/block-sanctum2
-rwxr-xr-xblocks/block-vol8
-rwxr-xr-xblocks/block-vpn6
-rwxr-xr-xbridge-sync88
-rwxr-xr-xbt-fix4
l---------claude2
-rwxr-xr-x[l---------]hledger-webbin142 -> 130899496 bytes
-rwxr-xr-xrecord-output124
-rwxr-xr-xrecord-voice82
-rwxr-xr-xsanctum-battery25
-rwxr-xr-xsanctum-term2
-rwxr-xr-xshield-backup175
-rwxr-xr-xssh-tunnel-all31
-rwxr-xr-xssh-tunnel-down3
-rwxr-xr-xssh-tunnel-up4
-rwxr-xr-xtst4
-rwxr-xr-xtzat8
-rwxr-xr-xusb-tether55
-rwxr-xr-xwatchdir42
26 files changed, 532 insertions, 208 deletions
diff --git a/.gitignore b/.gitignore
index 0798a46..c17d396 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,9 @@
*@
+claude
+faker
+pudb
+pylsp
+rexi
+sfeed.sh yt.dlp
+archive/
+docs/
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..3904d0c
--- /dev/null
+++ b/README.md
@@ -0,0 +1,2 @@
+A collection of random scripts accumulated over time to sort out various problems or
+make life easier or just for experimentation. Not much to see anyway...
diff --git a/archive/bridge-sync.sh.bak b/archive/bridge-sync.sh.bak
deleted file mode 100644
index 7aecb75..0000000
--- a/archive/bridge-sync.sh.bak
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-CERT_FILE="$HOME/.config/isync/proton-bridge.pem"
-
-echo "[1] Restart Bridge"
-systemctl --user restart protonmail-bridge.service
-
-echo "[2] Wait for Bridge IMAP port"
-for i in {1..30}; do
- ss -ltn '( sport = :1143 )' | grep -q 1143 && break
- sleep 1
-done
-
-ss -ltn '( sport = :1143 )' | grep -q 1143 || {
- echo "Bridge did not start"; exit 1; }
-
-echo "[3] Refresh cert"
-systemctl --user start proton-bridge-cert-refresh.service
-
-echo "[4] Wait for cert"
-for i in {1..10}; do
- [ -s "$CERT_FILE" ] && break
- sleep 1
-done
-
-[ -s "$CERT_FILE" ] || { echo "Cert not created"; exit 1; }
-
-echo "[5] Run mbsync"
-mbsync -a -V
-
diff --git a/blocks/block-cpu b/blocks/block-cpu
new file mode 100755
index 0000000..3491608
--- /dev/null
+++ b/blocks/block-cpu
@@ -0,0 +1,23 @@
+#!/bin/sh
+# CPU usage from /proc/stat deltas. Cheaper than `top -bn1`.
+STATE=/tmp/block-cpu.state
+
+read -r _ u n s i io irq sirq st _ < /proc/stat
+total=$((u+n+s+i+io+irq+sirq+st))
+idle=$((i+io))
+
+if [ -r "$STATE" ]; then
+ read -r prev_total prev_idle < "$STATE"
+ dt=$((total - prev_total))
+ di=$((idle - prev_idle))
+ if [ "$dt" -gt 0 ]; then
+ usage=$(( ( (dt - di) * 100 ) / dt ))
+ else
+ usage=0
+ fi
+else
+ usage=0
+fi
+
+echo "$total $idle" > "$STATE"
+echo "${usage}%"
diff --git a/blocks/block-datetime b/blocks/block-datetime
new file mode 100755
index 0000000..dba886f
--- /dev/null
+++ b/blocks/block-datetime
@@ -0,0 +1,2 @@
+#!/bin/sh
+date '+%d %a %H:%M'
diff --git a/blocks/block-mem b/blocks/block-mem
new file mode 100755
index 0000000..50fd29b
--- /dev/null
+++ b/blocks/block-mem
@@ -0,0 +1,2 @@
+#!/bin/sh
+free -m | awk '/^Mem/{printf "%dM\n", $3}'
diff --git a/blocks/block-net b/blocks/block-net
new file mode 100755
index 0000000..d103ae9
--- /dev/null
+++ b/blocks/block-net
@@ -0,0 +1,7 @@
+#!/bin/sh
+iface=$(ip route show default | awk '/default/{print $5; exit}')
+if [ -n "$iface" ] && [ "$(cat /sys/class/net/$iface/carrier 2>/dev/null)" = "1" ]; then
+ echo "online"
+else
+ echo "offline"
+fi
diff --git a/blocks/block-sanctum b/blocks/block-sanctum
new file mode 100755
index 0000000..57e6275
--- /dev/null
+++ b/blocks/block-sanctum
@@ -0,0 +1,2 @@
+#!/bin/sh
+exec ~/.local/bin/sanctum-battery
diff --git a/blocks/block-vol b/blocks/block-vol
new file mode 100755
index 0000000..cb06750
--- /dev/null
+++ b/blocks/block-vol
@@ -0,0 +1,8 @@
+#!/bin/sh
+if command -v pamixer >/dev/null 2>&1; then
+ pamixer --get-volume-human 2>/dev/null
+elif command -v amixer >/dev/null 2>&1; then
+ amixer get Master | awk -F'[][]' 'END{print $2}'
+else
+ echo "n/a"
+fi
diff --git a/blocks/block-vpn b/blocks/block-vpn
new file mode 100755
index 0000000..28ae549
--- /dev/null
+++ b/blocks/block-vpn
@@ -0,0 +1,6 @@
+#!/bin/sh
+if ip link show wg-vps >/dev/null 2>&1; then
+ echo "on"
+else
+ echo "off"
+fi
diff --git a/bridge-sync b/bridge-sync
deleted file mode 100755
index b92f849..0000000
--- a/bridge-sync
+++ /dev/null
@@ -1,88 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-CERT_FILE="${HOME}/.config/isync/proton-bridge.pem"
-
-BRIDGE_UNIT="protonmail-bridge.service"
-IMAP_PORT="1143"
-
-# These paths match what your ps output shows.
-BRIDGE_CHILD_PATH="/usr/lib/protonmail/bridge/bridge"
-BRIDGE_LAUNCHER_PATH="/usr/bin/protonmail-bridge"
-
-CERT_REFRESH_UNIT="proton-bridge-cert-refresh.service"
-
-port_listening() {
- ss -ltn "( sport = :${IMAP_PORT} )" | grep -q ":${IMAP_PORT}"
-}
-
-echo "[0] Preconditions"
-command -v ss >/dev/null
-command -v mbsync >/dev/null
-command -v systemctl >/dev/null
-
-echo "[1] Stop Bridge (systemd user service)"
-systemctl --user stop "${BRIDGE_UNIT}" || true
-
-echo "[1.1] Kill any remaining processes in unit cgroup"
-# If stop didn't fully terminate, this forces remaining processes in the unit's cgroup to die.
-systemctl --user kill -s SIGKILL "${BRIDGE_UNIT}" || true
-
-echo "[1.2] Hard kill Bridge child (the one that tends to linger)"
-pkill -u "${USER}" -f "${BRIDGE_CHILD_PATH}" || true
-
-echo "[1.3] Optional: kill launcher if it lingers"
-pkill -u "${USER}" -f "${BRIDGE_LAUNCHER_PATH}" || true
-
-echo "[1.4] Wait until IMAP port ${IMAP_PORT} is closed"
-for i in {1..15}; do
- port_listening || break
- sleep 1
-done
-
-if port_listening; then
- echo "ERROR: Port ${IMAP_PORT} still open after stop/kill."
- echo "Diagnostics:"
- ss -ltnp | grep ":${IMAP_PORT}" || true
- ps -u "${USER}" -o pid,comm,args | grep -E 'protonmail|/usr/lib/protonmail/bridge/bridge' | grep -v grep || true
- exit 1
-fi
-
-echo "[2] Start Bridge"
-systemctl --user start "${BRIDGE_UNIT}"
-
-echo "[2.1] Wait for Bridge IMAP port ${IMAP_PORT}"
-for i in {1..30}; do
- port_listening && break
- sleep 1
-done
-
-if ! port_listening; then
- echo "ERROR: Bridge did not start (port ${IMAP_PORT} not listening)."
- echo "Diagnostics:"
- systemctl --user status "${BRIDGE_UNIT}" --no-pager || true
- journalctl --user -u "${BRIDGE_UNIT}" -n 80 --no-pager || true
- exit 1
-fi
-
-echo "[3] Refresh cert"
-systemctl --user start "${CERT_REFRESH_UNIT}"
-
-echo "[3.1] Wait for cert: ${CERT_FILE}"
-for i in {1..10}; do
- [ -s "${CERT_FILE}" ] && break
- sleep 1
-done
-
-if [ ! -s "${CERT_FILE}" ]; then
- echo "ERROR: Cert not created at ${CERT_FILE}"
- echo "Diagnostics:"
- systemctl --user status "${CERT_REFRESH_UNIT}" --no-pager || true
- journalctl --user -u "${CERT_REFRESH_UNIT}" -n 80 --no-pager || true
- ls -la "$(dirname "${CERT_FILE}")" || true
- exit 1
-fi
-
-echo "[4] Run mbsync"
-mbsync -a -V
-
diff --git a/bt-fix b/bt-fix
index 1d9cfc4..76e32b7 100755
--- a/bt-fix
+++ b/bt-fix
@@ -1,10 +1,10 @@
#!/bin/sh
# Reset Bluetooth adapter (run as root)
-systemctl stop bluetooth.service
+service bluetooth stop
modprobe -r btusb
modprobe btusb
-systemctl start bluetooth.service
+service bluetooth start
rfkill unblock bluetooth
bluetoothctl power on
diff --git a/claude b/claude
index 7571232..e580bec 120000
--- a/claude
+++ b/claude
@@ -1 +1 @@
-/home/lukasz/.local/share/claude/versions/2.1.138 \ No newline at end of file
+/home/lukasz/.local/share/claude/versions/2.1.144 \ No newline at end of file
diff --git a/hledger-web b/hledger-web
index 98dfc41..1cff9b8 120000..100755
--- a/hledger-web
+++ b/hledger-web
Binary files differ
diff --git a/record-output b/record-output
new file mode 100755
index 0000000..ab48bdb
--- /dev/null
+++ b/record-output
@@ -0,0 +1,124 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+OUTPUT="voice"
+FORMAT="mp3"
+BITRATE="128k"
+SOURCE=""
+GAIN="6dB"
+NORMALIZE=1
+PROBE=0
+
+usage() {
+ cat <<EOF
+Usage: $0 -o name [-f mp3|wav] [-b bitrate] [-s source] [-g gain] [-n] [-p]
+
+Records the currently active audio output (whatever is playing through the
+default sink). Auto-detects the correct monitor source.
+
+Options:
+ -o NAME Output basename (without extension)
+ -f FORMAT mp3 (default) or wav
+ -b BITRATE MP3 bitrate (default 128k)
+ -s SOURCE Override monitor source (default: auto-detect from default sink)
+ -g GAIN Pre-normalization gain (default 8dB; set 0dB to disable)
+ -n No normalization (raw capture)
+ -p Probe mode: 5s test recording, print levels, exit
+ -h Help
+
+Notes:
+ Pre-gain default (8dB) is tuned for an attenuated chain (e.g. Bluetooth sink
+ at ~0.35 + app-level stream attenuation). Run -p after any sink or headphone
+ change; chain attenuation is device-specific.
+
+Examples:
+ $0 -o lecture
+ $0 -o music -f wav -g 6dB
+ $0 -p # check levels before committing to a long recording
+EOF
+ exit 0
+}
+
+while getopts "o:f:b:s:g:nph" opt; do
+ case "$opt" in
+ o) OUTPUT="$OPTARG" ;;
+ f) FORMAT="$OPTARG" ;;
+ b) BITRATE="$OPTARG" ;;
+ s) SOURCE="$OPTARG" ;;
+ g) GAIN="$OPTARG" ;;
+ n) NORMALIZE=0 ;;
+ p) PROBE=1 ;;
+ h) usage ;;
+ *) usage ;;
+ esac
+done
+
+# Auto-detect monitor of the default sink (what the user is actually hearing)
+if [ -z "$SOURCE" ]; then
+ DEFAULT_SINK=$(pactl get-default-sink)
+ SOURCE="${DEFAULT_SINK}.monitor"
+fi
+
+# Verify the source exists before invoking ffmpeg
+if ! pactl list sources short | awk '{print $2}' | grep -Fxq "$SOURCE"; then
+ echo "Error: monitor source not found: $SOURCE" >&2
+ echo "Available sources:" >&2
+ pactl list sources short | awk '{print " " $2}' >&2
+ exit 1
+fi
+
+# Build audio filter chain
+FILTER=""
+if [ "$NORMALIZE" -eq 1 ]; then
+ FILTER="volume=${GAIN},loudnorm=I=-16:TP=-1.5:LRA=11"
+elif [ "$GAIN" != "0dB" ]; then
+ FILTER="volume=${GAIN}"
+fi
+
+FORMAT=$(echo "$FORMAT" | tr '[:upper:]' '[:lower:]')
+
+# Probe mode: short capture, report levels, exit
+if [ "$PROBE" -eq 1 ]; then
+ echo "Probing $SOURCE for 5 seconds..."
+ PROBE_OUT=$(ffmpeg -hide_banner -nostats -loglevel info \
+ -f pulse -i "$SOURCE" -t 5 -af "volumedetect" -f null - 2>&1) || true
+ LEVELS=$(echo "$PROBE_OUT" | grep -E "mean_volume|max_volume" || true)
+ if [ -z "$LEVELS" ]; then
+ echo "No level data — source emitted silence or ffmpeg failed."
+ echo
+ echo "ffmpeg output (last 20 lines):"
+ echo "$PROBE_OUT" | tail -20
+ else
+ echo "$LEVELS"
+ echo
+ echo "Current gain: -g ${GAIN}"
+ echo
+ echo "Reference:"
+ echo " mean_volume near -16 dB good for voice"
+ echo " mean_volume below -25 dB increase -g or raise sink volume"
+ echo " max_volume above -1 dB reduce -g (risk of clipping)"
+ fi
+ exit 0
+fi
+
+# Assemble ffmpeg invocation
+FILE="${OUTPUT}.${FORMAT}"
+ARGS=(-f pulse -i "$SOURCE" -ac 2)
+[ -n "$FILTER" ] && ARGS+=(-af "$FILTER")
+
+case "$FORMAT" in
+ mp3) ARGS+=(-c:a libmp3lame -b:a "$BITRATE") ;;
+ wav) : ;;
+ *)
+ echo "Error: unsupported format '$FORMAT' (use mp3 or wav)" >&2
+ exit 1
+ ;;
+esac
+
+echo "Recording: $SOURCE"
+echo "Filter: ${FILTER:-(none)}"
+echo "Output: $FILE"
+echo "Press Ctrl+C to stop."
+echo
+
+ffmpeg "${ARGS[@]}" "$FILE"
diff --git a/record-voice b/record-voice
new file mode 100755
index 0000000..ce68cae
--- /dev/null
+++ b/record-voice
@@ -0,0 +1,82 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+OUTPUT="voice"
+BITRATE="128k"
+FORMAT="mp3"
+
+usage() {
+ echo "Usage: $0 -o output_name [options]"
+ echo
+ echo "Options:"
+ echo " -o NAME Output filename (without extension)"
+ echo " -b BITRATE MP3 bitrate"
+ echo " -f FORMAT Output format: mp3 or wav"
+ echo " -h Show this help message"
+ echo
+ echo "Available MP3 bitrates:"
+ echo " 64k Low quality / smallest files"
+ echo " 96k Good for speech"
+ echo " 128k Very good speech quality (default)"
+ echo " 192k High quality"
+ echo " 320k Maximum MP3 quality"
+ echo
+ echo "Examples:"
+ echo " $0 -o meeting"
+ echo " $0 -o podcast -b 192k"
+ echo " $0 -o lecture -f wav"
+ echo
+ exit 0
+}
+
+while getopts "o:b:f:h" opt; do
+ case "$opt" in
+ o) OUTPUT="$OPTARG" ;;
+ b) BITRATE="$OPTARG" ;;
+ f) FORMAT="$OPTARG" ;;
+ h) usage ;;
+ *) usage ;;
+ esac
+done
+
+FORMAT=$(echo "$FORMAT" | tr '[:upper:]' '[:lower:]')
+
+case "$FORMAT" in
+ mp3)
+ FILE="${OUTPUT}.mp3"
+
+ echo "Recording MP3 to: $FILE"
+ echo "Bitrate: $BITRATE"
+ echo "Press Ctrl+C to stop."
+ echo
+
+ ffmpeg \
+ -f pulse \
+ -i default \
+ -ac 1 \
+ -c:a libmp3lame \
+ -b:a "$BITRATE" \
+ "$FILE"
+ ;;
+
+ wav)
+ FILE="${OUTPUT}.wav"
+
+ echo "Recording WAV to: $FILE"
+ echo "Press Ctrl+C to stop."
+ echo
+
+ ffmpeg \
+ -f pulse \
+ -i default \
+ -ac 1 \
+ "$FILE"
+ ;;
+
+ *)
+ echo "Error: unsupported format '$FORMAT'"
+ echo "Supported formats: mp3, wav"
+ exit 1
+ ;;
+esac
diff --git a/sanctum-battery b/sanctum-battery
new file mode 100755
index 0000000..e160d75
--- /dev/null
+++ b/sanctum-battery
@@ -0,0 +1,25 @@
+#!/bin/sh
+# Query sanctum battery state via persistent SSH.
+
+out=$(ssh -o ConnectTimeout=3 -o BatchMode=yes sanctum-status \
+ 'sysctl -n hw.acpi.battery.life hw.acpi.acline' 2>/tmp/sanctum-battery.err)
+
+if [ -z "$out" ]; then
+ echo "BAT ?"
+ exit 0
+fi
+
+life=$(echo "$out" | sed -n '1p')
+acline=$(echo "$out" | sed -n '2p')
+
+if [ "$acline" = "1" ]; then
+ flag="AC"
+else
+ flag="-"
+fi
+
+if [ "$acline" = "1" ] && [ "$life" -ge 60 ]; then
+ echo "BAT ${life}% ${flag} !"
+else
+ echo "BAT ${life}% ${flag}"
+fi
diff --git a/sanctum-term b/sanctum-term
new file mode 100755
index 0000000..15db2af
--- /dev/null
+++ b/sanctum-term
@@ -0,0 +1,2 @@
+#!/bin/sh
+exec st -n sanctum -C "#000000@257" -C "#ffffff@256" -e ssh sanctum
diff --git a/shield-backup b/shield-backup
index ccaff5b..1c95a5d 100755
--- a/shield-backup
+++ b/shield-backup
@@ -2,7 +2,7 @@
set -euo pipefail
export PATH="/usr/sbin:/sbin:/usr/bin:/bin:$PATH"
-RCLONE_CONFIG="$HOME/.config/rclone/rclone.conf"
+
#################### CONFIG – EDIT THESE ####################
# LUKS2 block device
@@ -23,59 +23,141 @@ BACKUP_ITEMS=(
# Machine identifier (destination subdir on the LUKS volume)
MACHINE_DIR="T480"
-#################### INTERNALS – NO NEED TO EDIT ############
-
-RSYNC_EXCLUDES_FILE="/tmp/rsync_excludes_$$.txt"
-
-cat > "${RSYNC_EXCLUDES_FILE}" <<'EOF'
+# rsync exclude patterns (passed via stdin to --exclude-from=-)
+# Paths are relative to each rsync source root (i.e. $HOME for the home backup).
+read -r -d '' RSYNC_EXCLUDES <<'EOF' || true
+# === Top-level junk ===
downloads/
-# Caches & regenerable state
+Downloads/
+tmp/
+.tmp/
+
+# === All caches (3.9G in .cache alone) ===
.cache/
+
+# === Browsers (rebuilt on next launch) ===
+.mozilla/
+.mullvad-browser/
+
+# === Shell / history / runtime state ===
.fasd
.viminfo
-.zcompdump
+.zcompdump*
+.lesshst
.sqlite_history
+.python_history
+.node_repl_history
.wget-hsts
-.dbus/
+.xsession-errors*
.Xauthority
+.ICEauthority
+.dbus/
.pki/
-tmp/
+.gvfs/
+
+# === Trash ===
+.local/share/Trash/
+.Trash-*/
+
+# === Claude Code old versions (884M, current one re-fetches) ===
+.local/share/claude/versions/
+
+# === Haskell / cabal (1.9G total, fully regenerable) ===
+.cache/cabal/
+.local/state/cabal/
+
+# === Rust / cargo registry (152M, regenerable from Cargo.lock) ===
+.cargo/registry/
+.cargo/git/
+
+# === Python: venvs, caches, bytecode (anywhere in tree) ===
+__pycache__/
+*.pyc
+*.pyo
+.mypy_cache/
+.pytest_cache/
+.ruff_cache/
+.tox/
+.venv/
+venv/
+.virtualenvs/
+.local/share/pipx/
+
+# === Node / JS ===
+node_modules/
+.npm/
+.yarn/cache/
+.pnpm-store/
+
+# === Build artifacts in repos ===
+build/
+dist/
+target/
+.gradle/
+.m2/repository/
-# Browser internals
-.mozilla/firefox/*/cache2/
-.mozilla/firefox/*/storage/
-.mozilla/firefox/*/datareporting/
-.mullvad-browser/*/cache2/
-.mullvad-browser/*/storage/
+# === LaTeX caches ===
+.texlive*/texmf-var/
+.texlive*/texmf-cache/
-# Crypto node data (re-syncs)
+# === Java runtime junk ===
+.java/
+
+# === Notmuch index (668M, rebuild with `notmuch new`) ===
+.local/share/mail/.notmuch/xapian/
+
+# === Whisper.cpp models (754M, redownloadable) ===
+git/whisper.cpp/models/
+git/whisper.cpp/build/
+
+# === Reinstallable third-party software in ~/opt ===
+opt/tor-browser/
+opt/monero-gui-*/
+opt/Electrum-*/
+
+# === Themes (509M, reinstall from upstream) ===
+.themes/gruvbox-gtk-theme/
+
+# === Crypto node chain data (re-syncs) ===
.bitmonero/
.shared-ringdb/
+.ethereum/geth/chaindata/
+.bitcoin/blocks/
+.bitcoin/chainstate/
-# Large reinstallable tooling
-.cargo/registry
-.cargo/git
-.texlive2025/
+# === Electron / chat app caches ===
+.config/Signal/Cache/
+.config/Code/Cache/
+.config/Code/CachedData/
+.config/Code/logs/
-# Java runtime junk
-.java/
+# === Flatpak / Snap caches ===
+.var/app/*/cache/
+snap/*/common/.cache/
+
+# === OS junk ===
+.DS_Store
+Thumbs.db
+*.swp
+*.swo
+*~
+core
+core.*
EOF
+#################### INTERNALS – NO NEED TO EDIT ############
+
need_cmd() { command -v "$1" >/dev/null 2>&1 || { echo "ERROR: missing command: $1" >&2; exit 1; }; }
cleanup() {
echo
echo ">>> Cleaning up..."
- rm -f "${RSYNC_EXCLUDES_FILE}"
-
- # Try to unmount, if mounted
if mountpoint -q "${LUKS_MOUNTPOINT}"; then
echo ">>> Unmounting ${LUKS_MOUNTPOINT}..."
sudo umount "${LUKS_MOUNTPOINT}" || true
fi
- # Close LUKS mapping if it exists
if [ -e "/dev/mapper/${LUKS_NAME}" ]; then
echo ">>> Closing LUKS mapping ${LUKS_NAME}..."
sudo cryptsetup close "${LUKS_NAME}" || true
@@ -84,17 +166,15 @@ cleanup() {
trap cleanup EXIT
need_cmd cryptsetup
-need_cmd rclone
need_cmd rsync
need_cmd mountpoint
-# Cache sudo credentials early to avoid surprises mid-run
+# Cache sudo credentials early
sudo -v
echo ">>> Ensuring mountpoint exists: ${LUKS_MOUNTPOINT}"
sudo mkdir -p "${LUKS_MOUNTPOINT}"
-# Check if already open
if [ -e "/dev/mapper/${LUKS_NAME}" ]; then
echo ">>> WARNING: /dev/mapper/${LUKS_NAME} already exists, assuming already open."
else
@@ -102,13 +182,11 @@ else
sudo cryptsetup open "${LUKS_DEVICE}" "${LUKS_NAME}"
fi
-# At this point /dev/mapper/${LUKS_NAME} must exist
if [ ! -e "/dev/mapper/${LUKS_NAME}" ]; then
echo "ERROR: /dev/mapper/${LUKS_NAME} not found after cryptsetup open." >&2
exit 1
fi
-# Mount if not already mounted
if mountpoint -q "${LUKS_MOUNTPOINT}"; then
echo ">>> WARNING: ${LUKS_MOUNTPOINT} already mounted."
else
@@ -118,21 +196,8 @@ fi
echo ">>> LUKS volume mounted at ${LUKS_MOUNTPOINT}"
-# Ensure SharePoint destinations exist in root of shield
-sudo mkdir -p \
- "${LUKS_MOUNTPOINT}/SP_Administration" \
- "${LUKS_MOUNTPOINT}/SP_Operations" \
- "${LUKS_MOUNTPOINT}/SP_Skyscale"
-
-echo ">>> Starting rclone syncs (SharePoint -> ${LUKS_MOUNTPOINT}/SP_*)..."
-rclone --config "$RCLONE_CONFIG" sync 'SP_Administration:' "${LUKS_MOUNTPOINT}/SP_Administration" --create-empty-src-dirs --fast-list --progress
-rclone --config "$RCLONE_CONFIG" sync 'SP_Operations:' "${LUKS_MOUNTPOINT}/SP_Operations" --create-empty-src-dirs --fast-list --progress
-rclone --config "$RCLONE_CONFIG" sync 'SP_SkyscaleCommerce:' "${LUKS_MOUNTPOINT}/SP_Skyscale" --create-empty-src-dirs --fast-list --progress
-echo ">>> All rclone syncs finished."
-
echo ">>> Starting rsync backups of local folders -> ${LUKS_MOUNTPOINT}/${MACHINE_DIR}/..."
-# Ensure machine root exists
sudo mkdir -p "${LUKS_MOUNTPOINT}/${MACHINE_DIR}"
for SRC in "${BACKUP_ITEMS[@]}"; do
@@ -158,12 +223,24 @@ for SRC in "${BACKUP_ITEMS[@]}"; do
sudo mkdir -p "${DEST}"
echo ">>> rsync: ${SRC} -> ${DEST}"
- rsync -a --delete --progress \
- --exclude-from="${RSYNC_EXCLUDES_FILE}" \
+ set +e
+ sudo rsync -a --delete --progress \
+ --exclude-from=- \
"${SRC%/}/" \
- "${DEST}/"
+ "${DEST}/" <<< "${RSYNC_EXCLUDES}"
+ RSYNC_RC=$?
+ set -e
+ case "${RSYNC_RC}" in
+ 0) ;;
+ 23|24)
+ echo ">>> rsync finished with code ${RSYNC_RC} (some files skipped/vanished); continuing."
+ ;;
+ *)
+ echo "ERROR: rsync failed with code ${RSYNC_RC} on ${SRC}" >&2
+ exit "${RSYNC_RC}"
+ ;;
+ esac
done
echo ">>> All rsync backups finished."
echo ">>> Unmounting and closing LUKS (via trap)..."
-# cleanup() will run automatically on script exit
diff --git a/ssh-tunnel-all b/ssh-tunnel-all
deleted file mode 100755
index 9c35202..0000000
--- a/ssh-tunnel-all
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/usr/bin/env zsh
-set -euo pipefail
-
-SOCK="${XDG_RUNTIME_DIR:-/tmp}/sanctum-all.sock"
-HOST="lukasz@192.168.33.5"
-PORT="57385"
-
-if [[ -S "$SOCK" ]]; then
- if ssh -S "$SOCK" -O check -p "$PORT" "$HOST" >/dev/null 2>&1; then
- echo "Tunnel already running"
- exit 0
- else
- rm -f "$SOCK"
- fi
-fi
-
-ssh -fN \
- -M \
- -S "$SOCK" \
- -p "$PORT" \
- -L 127.0.0.1:18080:127.0.0.1:8080 \
- -L 127.0.0.1:8502:127.0.0.1:8502 \
- -L 127.0.0.1:5055:127.0.0.1:5055 \
- -L 127.0.0.1:8000:127.0.0.1:8000 \
- -L 127.0.0.1:4444:127.0.0.1:4444 \
- -L 127.0.0.1:7070:127.0.0.1:7070 \
- -L 127.0.0.1:7659:127.0.0.1:7659 \
- -L 127.0.0.1:7660:127.0.0.1:7660 \
- "$HOST"
-
-echo "Tunnel started"
diff --git a/ssh-tunnel-down b/ssh-tunnel-down
new file mode 100755
index 0000000..5d74344
--- /dev/null
+++ b/ssh-tunnel-down
@@ -0,0 +1,3 @@
+#!/usr/bin/env zsh
+set -euo pipefail
+ssh -O exit sanctum-tunnel 2>/dev/null && echo "Tunnel stopped" || echo "No tunnel running"
diff --git a/ssh-tunnel-up b/ssh-tunnel-up
new file mode 100755
index 0000000..b104e23
--- /dev/null
+++ b/ssh-tunnel-up
@@ -0,0 +1,4 @@
+#!/usr/bin/env zsh
+set -euo pipefail
+ssh -fN sanctum-tunnel
+echo "Tunnel started"
diff --git a/tst b/tst
new file mode 100755
index 0000000..3febd44
--- /dev/null
+++ b/tst
@@ -0,0 +1,4 @@
+#!/bin/sh
+# Launch tabbed hosting st.
+# Usage: tst [extra st args]
+exec tabbed -c -r 2 st -w '' "$@"
diff --git a/tzat b/tzat
new file mode 100755
index 0000000..341a2dc
--- /dev/null
+++ b/tzat
@@ -0,0 +1,8 @@
+#!/bin/sh
+# /home/lukasz/.local/bin/tzath
+tabbed -c -r 2 zathura -e '' "$@" &
+TPID=$!
+sleep 0.5
+# Send a synthetic Expose by toggling fullscreen briefly
+xdotool key --window "$(xdotool search --class tabbed | tail -1)" F11 F11 2>/dev/null
+wait $TPID
diff --git a/usb-tether b/usb-tether
index bbe16ed..1c12711 100755
--- a/usb-tether
+++ b/usb-tether
@@ -1,13 +1,56 @@
#!/bin/sh
-IFACE=$(ip -br a | grep 'enx' | awk '{print $1}')
+# USB tethering activator for Devuan
+# Brings up a USB-tethered interface, gets DHCP, and routes default traffic through it.
+set -eu
+
+# --- 1. Find the USB tethering interface ---
+IFACE=$(ip -br link | awk '/^(enx|usb|rndis)/ && /UP/ {print $1; exit}')
+if [ -z "$IFACE" ]; then
+ echo "Error: no USB tethering interface (enx*/usb*/rndis*) found that is UP." >&2
+ echo "Make sure the phone is plugged in and USB tethering is enabled." >&2
+ exit 1
+fi
+echo "Found USB interface: $IFACE"
+
+# --- 2. Pick a DHCP client ---
+if command -v dhcpcd >/dev/null 2>&1; then
+ DHCP_CMD="dhcpcd -q"
+elif command -v dhclient >/dev/null 2>&1; then
+ DHCP_CMD="dhclient -v"
+else
+ echo "Error: neither dhcpcd nor dhclient is installed." >&2
+ echo "Install one: sudo apt install dhcpcd5 (or) sudo apt install isc-dhcp-client" >&2
+ exit 1
+fi
+
+# --- 3. Bring the link up and request a lease ---
sudo ip link set "$IFACE" up
-sudo dhcpcd "$IFACE"
+echo "Requesting DHCP lease via $DHCP_CMD ..."
+sudo $DHCP_CMD "$IFACE"
-GATEWAY=$(ip route | grep "$IFACE" | awk '/default/ {print $3}')
+# --- 4. Wait for the default route to populate ---
+GATEWAY=""
+for i in 1 2 3 4 5 6 7 8 9 10; do
+ GATEWAY=$(ip route show dev "$IFACE" | awk '/default/ {print $3; exit}')
+ [ -n "$GATEWAY" ] && break
+ sleep 1
+done
-sudo ip route del default
-sudo ip route add default via "$GATEWAY" dev "$IFACE"
+if [ -z "$GATEWAY" ]; then
+ echo "Error: could not determine gateway on $IFACE after 10s." >&2
+ ip addr show "$IFACE" >&2
+ exit 1
+fi
+echo "Gateway: $GATEWAY"
-echo "USB tethering active on $IFACE"
+# --- 5. Replace the default route, preferring this interface ---
+# `ip route replace` is atomic — no need to delete first, and it won't fail
+# if there's no existing default. We use a low metric so this route wins.
+sudo ip route replace default via "$GATEWAY" dev "$IFACE" metric 50
+# --- 6. Confirm ---
+echo ""
+echo "USB tethering active on $IFACE"
+echo "Current default routes:"
+ip route show default
diff --git a/watchdir b/watchdir
new file mode 100755
index 0000000..3499bf8
--- /dev/null
+++ b/watchdir
@@ -0,0 +1,42 @@
+#!/bin/sh
+# Usage: watchdir [DIR] [LOGFILE]
+# Recursively logs file additions/modifications/deletions.
+
+set -eu
+
+DIR="${1:-$PWD}"
+LOG="${2:-$DIR/changes.log}"
+
+if [ ! -d "$DIR" ]; then
+ printf 'Not a directory: %s\n' "$DIR" >&2
+ exit 1
+fi
+
+DIR=$(readlink -f "$DIR")
+LOG=$(readlink -f "$LOG")
+
+# Exclude patterns (POSIX extended regex, OR-joined).
+# Append more lines below to extend.
+EXCLUDES="${LOG}\$"
+EXCLUDES="${EXCLUDES}|/\\.git(/|\$)"
+# EXCLUDES="${EXCLUDES}|/node_modules(/|\$)"
+# EXCLUDES="${EXCLUDES}|\\.swp\$"
+EXCLUDE_RE="($EXCLUDES)"
+
+printf 'Watching: %s\n' "$DIR"
+printf 'Logging to: %s\n' "$LOG"
+
+inotifywait -mr \
+ --exclude "$EXCLUDE_RE" \
+ -e close_write,create,delete,moved_to,moved_from \
+ --format '%T|%e|%w%f' --timefmt '%F %T' \
+ "$DIR" |
+while IFS='|' read -r ts ev path; do
+ case "$ev" in
+ CREATE*|MOVED_TO*) action=added ;;
+ CLOSE_WRITE*) action=modified ;;
+ DELETE*|MOVED_FROM*) action=deleted ;;
+ *) action="$ev" ;;
+ esac
+ printf '%s|%s|%s\n' "$ts" "$action" "$path" >> "$LOG"
+done