#!/usr/bin/bash # shellcheck disable=SC2010 # diagnostic; ls|grep on /dev listing is intentional # # console/setup.sh — deploy console management on pfv-tsys4 # # Orchestrates the full setup: # 1. Ensures ser2net + conman are installed # 2. Copies mapping.txt to the target host (if running remotely) # 3. Runs generate-config.sh to produce udev rules + ser2net.yaml + conman.conf # 4. Reloads udev, creates /dev/consoles/ symlinks # 5. Restarts ser2net (TCP ports on Tailscale IP) # 6. Enables + starts conmand (logging + multiplexing) # 7. Verifies # # This script is IDEMPOTENT — safe to run multiple times. # # Usage: # PROX_HOST=pfv-tsys4 bash tests/remote.sh prox-file console/setup.sh # set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" echo "============================================" echo " Console Management Setup" echo " Host: $(hostname) $(date)" echo "============================================" # --- 1. Install dependencies --- echo "" echo "--- [1/7] Checking dependencies ---" NEED_INSTALL=() dpkg -l ser2net 2>/dev/null | grep -q '^ii' && echo " ser2net: installed" || NEED_INSTALL+=(ser2net) dpkg -l conman 2>/dev/null | grep -q '^ii' && echo " conman: installed" || NEED_INSTALL+=(conman) if [ "${#NEED_INSTALL[@]}" -gt 0 ]; then echo " Installing: ${NEED_INSTALL[*]}" apt-get update -qq apt-get install -y -qq "${NEED_INSTALL[@]}" else echo " All dependencies present." fi # --- 2. Ensure mapping file is available --- echo "" echo "--- [2/7] Locating mapping file ---" MAPPING_FILE="" for candidate in \ "$SCRIPT_DIR/mapping.txt" \ "$(dirname "$0")/mapping.txt" \ "/root/console/mapping.txt" \ "/tmp/mapping.txt"; do if [ -f "$candidate" ]; then MAPPING_FILE="$candidate" break fi done if [ -z "$MAPPING_FILE" ]; then echo "FATAL: mapping.txt not found. Copy it to the target host." exit 1 fi echo " Using: $MAPPING_FILE" # --- 3. Generate configs --- echo "" echo "--- [3/7] Generating configs ---" export MAPPING_FILE bash "$(dirname "$0")/generate-config.sh" 2>&1 || bash "$SCRIPT_DIR/generate-config.sh" 2>&1 || { echo "FATAL: generate-config.sh failed." exit 1 } # --- 4. Reload udev + create symlinks --- echo "" echo "--- [4/7] Reloading udev rules ---" udevadm control --reload-rules # Try trigger first (works on some systems) for tty in /sys/class/tty/ttyUSB*; do [ -e "$tty" ] && udevadm trigger --action=add "$tty" 2>/dev/null || true done # Also try writing to uevent (forces udev reprocessing) for tty in /sys/class/tty/ttyUSB*; do [ -e "$tty/uevent" ] && echo "add" > "$tty/uevent" 2>/dev/null || true done sleep 2 # FALLBACK: if udev symlinks don't exist (common when devices are already # discovered — udev trigger doesn't always re-create symlinks for existing # devices), create them manually by matching ID_PATH. The udev rules will # handle future boots/hotplugs automatically. if [ ! -d /dev/consoles ] || [ -z "$(ls /dev/consoles/ 2>/dev/null)" ]; then echo " udev trigger didn't create symlinks. Creating manually..." mkdir -p /dev/consoles while IFS= read -r line; do line="${line%%#*}" line="$(echo "$line" | xargs)" [ -z "$line" ] && continue IFS='|' read -r _ name id_path _ _ <<< "$line" # Find the ttyUSB whose ID_PATH contains the mapping's id_path substring for tty in /dev/ttyUSB*; do [ -e "$tty" ] || continue DEV_IDPATH=$(udevadm info -q property -n "$tty" 2>/dev/null | grep ^ID_PATH= | cut -d= -f2) if echo "$DEV_IDPATH" | grep -q "$id_path"; then ln -sf "$tty" "/dev/consoles/$name" echo " ln -s $tty -> /dev/consoles/$name" break fi done done < "$MAPPING_FILE" fi echo " Stable symlinks:" ls -la /dev/consoles/ 2>/dev/null | grep -v '^total\|^d' | sed 's/^/ /' || echo " (none created)" # Verify each symlink resolves echo "" echo " Symlink verification:" while IFS= read -r line; do line="${line%%#*}" line="$(echo "$line" | xargs)" [ -z "$line" ] && continue IFS='|' read -r _ name id_path _ _ <<< "$line" if [ -e "/dev/consoles/$name" ]; then TARGET=$(readlink -f "/dev/consoles/$name") echo " [OK] /dev/consoles/$name -> $TARGET" else echo " [MISSING] /dev/consoles/$name (adapter unplugged or ID_PATH changed)" fi done < "$MAPPING_FILE" # --- 5. Restart ser2net --- echo "" echo "--- [5/7] Restarting ser2net ---" systemctl enable ser2net systemctl restart ser2net sleep 2 if systemctl is-active --quiet ser2net; then echo " ser2net is running (telnet rfc2217 accepters)." TS_IP=$(tailscale ip -4 2>/dev/null || echo "127.0.0.1") echo " Listening ports:" ss -tlnp | grep ser2net | grep -oE "${TS_IP}:[0-9]+" | sort -t: -k2 -n | sed 's/^/ /' else echo " WARNING: ser2net failed to start. Checking journal..." journalctl -u ser2net --no-pager -n 20 fi # --- 6. Enable + start conmand --- echo "" echo "--- [6/7] Starting conmand ---" # conman package on Debian may not ship a systemd unit. Create one if missing. if ! systemctl cat conmand >/dev/null 2>&1; then echo " No systemd unit for conmand — creating one..." cat > /etc/systemd/system/conmand.service <<'CONMAND_UNIT' [Unit] Description=ConMan (Console Manager) After=network.target ser2net.service Requires=ser2net.service [Service] Type=forking ExecStart=/usr/sbin/conmand -c /etc/conman.conf Restart=on-failure RestartSec=5 [Install] WantedBy=multi-user.target CONMAND_UNIT systemctl daemon-reload echo " Created /etc/systemd/system/conmand.service" fi # Kill any manually-started conmand first pkill -x conmand 2>/dev/null || true sleep 1 systemctl enable conmand 2>/dev/null || true systemctl restart conmand 2>/dev/null || true sleep 2 if systemctl is-active --quiet conmand; then echo " conmand is running." echo " Consoles:" conman -q 2>&1 | sed 's/^/ /' || true else echo " WARNING: conmand failed to start. Checking journal..." journalctl -u conmand --no-pager -n 20 2>/dev/null || true # Try manual start as fallback echo " Attempting manual start..." /usr/sbin/conmand -c /etc/conman.conf 2>&1 || true fi # --- 7. Summary --- echo "" echo "--- [7/7] Setup complete ---" echo "" echo " ser2net + conman architecture (telnet rfc2217):" echo " ser2net owns serial devices, exposes telnet(rfc2217) TCP ports" echo " conman connects via telnet for logging + multiplexing" echo "" echo " Connect from any Tailscale workstation:" echo " conman -d pfv-tsys4:7890 -f pfv-core-sw01" echo " conman -d pfv-tsys4:7890 -q # list consoles" echo "" echo " Direct telnet (emergency, conflicts with conman):" echo " ssh pfv-tsys4 'systemctl stop conmand'" echo " telnet pfv-tsys4 2001" echo " ssh pfv-tsys4 'systemctl start conmand'" echo "" echo " To regenerate after changing mapping.txt:" echo " bash generate-config.sh" echo " udevadm trigger" echo " systemctl restart ser2net conmand" echo "============================================"