From e8cf42f2f17151378574ee5b50f29904a1067bee Mon Sep 17 00:00:00 2001 From: Lukasz Kasprzak Date: Tue, 19 May 2026 18:38:39 +0200 Subject: added readme --- .gitignore | 8 ++ README.md | 2 + archive/bridge-sync.sh.bak | 31 -------- blocks/block-cpu | 23 ++++++ blocks/block-datetime | 2 + blocks/block-mem | 2 + blocks/block-net | 7 ++ blocks/block-sanctum | 2 + blocks/block-vol | 8 ++ blocks/block-vpn | 6 ++ bridge-sync | 88 ---------------------- bt-fix | 4 +- claude | 2 +- hledger-web | Bin 142 -> 130899496 bytes record-output | 124 +++++++++++++++++++++++++++++++ record-voice | 82 +++++++++++++++++++++ sanctum-battery | 25 +++++++ sanctum-term | 2 + shield-backup | 179 ++++++++++++++++++++++++++++++++------------- ssh-tunnel-all | 31 -------- ssh-tunnel-down | 3 + ssh-tunnel-up | 4 + tst | 4 + tzat | 8 ++ usb-tether | 55 ++++++++++++-- watchdir | 42 +++++++++++ 26 files changed, 534 insertions(+), 210 deletions(-) create mode 100644 README.md delete mode 100644 archive/bridge-sync.sh.bak create mode 100755 blocks/block-cpu create mode 100755 blocks/block-datetime create mode 100755 blocks/block-mem create mode 100755 blocks/block-net create mode 100755 blocks/block-sanctum create mode 100755 blocks/block-vol create mode 100755 blocks/block-vpn delete mode 100755 bridge-sync mode change 120000 => 100755 hledger-web create mode 100755 record-output create mode 100755 record-voice create mode 100755 sanctum-battery create mode 100755 sanctum-term delete mode 100755 ssh-tunnel-all create mode 100755 ssh-tunnel-down create mode 100755 ssh-tunnel-up create mode 100755 tst create mode 100755 tzat create mode 100755 watchdir 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 deleted file mode 120000 index 98dfc41..0000000 --- a/hledger-web +++ /dev/null @@ -1 +0,0 @@ -../state/cabal/store/ghc-9.6.6/hledger-web-1.52-e-hledger-web-f99d9bf291aa377724b7120cc87a3823a2f96994ead3e9140765ba87d007e3df/bin/hledger-web \ No newline at end of file diff --git a/hledger-web b/hledger-web new file mode 100755 index 0000000..1cff9b8 Binary files /dev/null and b/hledger-web 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 <&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/ + +# === LaTeX caches === +.texlive*/texmf-var/ +.texlive*/texmf-cache/ + +# === Java runtime junk === +.java/ -# Browser internals -.mozilla/firefox/*/cache2/ -.mozilla/firefox/*/storage/ -.mozilla/firefox/*/datareporting/ -.mullvad-browser/*/cache2/ -.mullvad-browser/*/storage/ +# === Notmuch index (668M, rebuild with `notmuch new`) === +.local/share/mail/.notmuch/xapian/ -# Crypto node data (re-syncs) -.bitmonero/ -.shared-ringdb/ +# === Whisper.cpp models (754M, redownloadable) === +git/whisper.cpp/models/ +git/whisper.cpp/build/ -# Large reinstallable tooling -.cargo/registry -.cargo/git -.texlive2025/ +# === Reinstallable third-party software in ~/opt === +opt/tor-browser/ +opt/monero-gui-*/ +opt/Electrum-*/ -# Java runtime junk -.java/ +# === 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/ + +# === Electron / chat app caches === +.config/Signal/Cache/ +.config/Code/Cache/ +.config/Code/CachedData/ +.config/Code/logs/ + +# === 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 -- cgit v1.3