diff options
| author | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-05-19 18:38:39 +0200 |
|---|---|---|
| committer | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-05-19 18:38:39 +0200 |
| commit | e8cf42f2f17151378574ee5b50f29904a1067bee (patch) | |
| tree | 86b4db80971ecf9818ad769bd8b7fa337d218731 | |
| parent | c3bfa44d1b6da88c184fc3312944cf47d1dfd7f2 (diff) | |
| download | bin-main.tar.gz bin-main.zip | |
| -rw-r--r-- | .gitignore | 8 | ||||
| -rw-r--r-- | README.md | 2 | ||||
| -rw-r--r-- | archive/bridge-sync.sh.bak | 31 | ||||
| -rwxr-xr-x | blocks/block-cpu | 23 | ||||
| -rwxr-xr-x | blocks/block-datetime | 2 | ||||
| -rwxr-xr-x | blocks/block-mem | 2 | ||||
| -rwxr-xr-x | blocks/block-net | 7 | ||||
| -rwxr-xr-x | blocks/block-sanctum | 2 | ||||
| -rwxr-xr-x | blocks/block-vol | 8 | ||||
| -rwxr-xr-x | blocks/block-vpn | 6 | ||||
| -rwxr-xr-x | bridge-sync | 88 | ||||
| -rwxr-xr-x | bt-fix | 4 | ||||
| l--------- | claude | 2 | ||||
| -rwxr-xr-x[l---------] | hledger-web | bin | 142 -> 130899496 bytes | |||
| -rwxr-xr-x | record-output | 124 | ||||
| -rwxr-xr-x | record-voice | 82 | ||||
| -rwxr-xr-x | sanctum-battery | 25 | ||||
| -rwxr-xr-x | sanctum-term | 2 | ||||
| -rwxr-xr-x | shield-backup | 175 | ||||
| -rwxr-xr-x | ssh-tunnel-all | 31 | ||||
| -rwxr-xr-x | ssh-tunnel-down | 3 | ||||
| -rwxr-xr-x | ssh-tunnel-up | 4 | ||||
| -rwxr-xr-x | tst | 4 | ||||
| -rwxr-xr-x | tzat | 8 | ||||
| -rwxr-xr-x | usb-tether | 55 | ||||
| -rwxr-xr-x | watchdir | 42 |
26 files changed, 532 insertions, 208 deletions
@@ -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 - @@ -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 @@ -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 Binary files differindex 98dfc41..1cff9b8 120000..100755 --- a/hledger-web +++ b/hledger-web 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" @@ -0,0 +1,4 @@ +#!/bin/sh +# Launch tabbed hosting st. +# Usage: tst [extra st args] +exec tabbed -c -r 2 st -w '' "$@" @@ -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 @@ -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 |
