port startup-related changes from broken tree
Restores the boot/launch chain customizations on top of the freshly-reset
baseline. Driving-model and per-feature changes (dashcamd, telemetry, gpsd,
bench mode, manager wiring) are deliberately left out and will be ported
piecemeal.
Brought in:
- launch_openpilot.sh: kill stale instances, run on_start.sh, background
vpn-monitor + nice-monitor, BENCH_MODE pass-through
- launch_chffrplus.sh: source build_preflight.sh, kill stale text-error UI
- build_only.sh, build_preflight.sh
- system/clearpilot/on_start.sh: SSH keys, ssh.service enable, git.hanson.xyz
Host config, WiFi radio on, run provision.sh
- system/clearpilot/provision.sh + provision_wrapper.sh: connectivity wait,
apt install (openvpn, curl, ccrypt, nodejs), Claude Code installer, git
remote fix, fast-forward origin/clearpilot, /data/quick_boot
- system/clearpilot/vpn-monitor.sh + vpn.ovpn: OpenVPN tunnel auto-connect
- system/clearpilot/nice-monitor.sh: keep claude processes at nice 19
- system/clearpilot/dev: id_ed25519.{cpt,pub.cpt}, GithubSshKeys, encrypt.sh
(DongleId-keyed instead of hardware-serial)
- system/clearpilot/tools/{decrypt,encrypt}: switch key source to DongleId
- system/clearpilot/startup_logo/{bg.jpg, generate_logo.sh, set_logo.sh}
- selfdrive/ui/qt/spinner{,.cc,.h}: new spinner with logo
Removed (baseline-only flow superseded by broken's on_start.sh+provision.sh):
- system/clearpilot/dev/on_start.sh
- system/clearpilot/dev/on_start_brian.sh.cpt
- system/clearpilot/dev/provision.sh
This commit is contained in:
Executable
+38
@@ -0,0 +1,38 @@
|
|||||||
|
#!/usr/bin/bash
|
||||||
|
# CLEARPILOT: build-only mode — compile without starting manager.
|
||||||
|
# On failure: shows error on screen (non-blocking) and exits nonzero with stderr output.
|
||||||
|
# On success: exits 0, does not start manager.
|
||||||
|
#
|
||||||
|
# Usage: su - comma -c "bash /data/openpilot/build_only.sh"
|
||||||
|
|
||||||
|
BASEDIR="/data/openpilot"
|
||||||
|
|
||||||
|
# Fix ownership — we edit as root, openpilot builds/runs as comma
|
||||||
|
sudo chown -R comma:comma "$BASEDIR"
|
||||||
|
|
||||||
|
# Kill stale error displays and any running manager/launch/managed processes
|
||||||
|
pkill -9 -f "selfdrive/ui/text" 2>/dev/null
|
||||||
|
pkill -9 -f 'launch_openpilot.sh' 2>/dev/null
|
||||||
|
pkill -9 -f 'launch_chffrplus.sh' 2>/dev/null
|
||||||
|
pkill -9 -f 'python.*manager.py' 2>/dev/null
|
||||||
|
pkill -9 -f 'selfdrive\.' 2>/dev/null
|
||||||
|
pkill -9 -f 'system\.' 2>/dev/null
|
||||||
|
pkill -9 -f './ui' 2>/dev/null
|
||||||
|
sleep 1
|
||||||
|
|
||||||
|
source "$BASEDIR/launch_env.sh"
|
||||||
|
|
||||||
|
ln -sfn "$BASEDIR" /data/pythonpath
|
||||||
|
export PYTHONPATH="$BASEDIR"
|
||||||
|
|
||||||
|
# Hardware init (GPU perms)
|
||||||
|
sudo chgrp gpu /dev/adsprpc-smd /dev/ion /dev/kgsl-3d0 2>/dev/null
|
||||||
|
sudo chmod 660 /dev/adsprpc-smd /dev/ion /dev/kgsl-3d0 2>/dev/null
|
||||||
|
|
||||||
|
# Preflight: create dirs git can't track
|
||||||
|
source "$BASEDIR/build_preflight.sh"
|
||||||
|
|
||||||
|
cd "$BASEDIR/selfdrive/manager"
|
||||||
|
rm -f "$BASEDIR/prebuilt"
|
||||||
|
|
||||||
|
BUILD_ONLY=1 exec ./build.py
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
#!/usr/bin/bash
|
||||||
|
# CLEARPILOT: build preflight — create directories and fix state that
|
||||||
|
# git cannot track but the build requires. Called by build_only.sh and
|
||||||
|
# launch_chffrplus.sh before scons runs.
|
||||||
|
|
||||||
|
BASEDIR="${BASEDIR:-/data/openpilot}"
|
||||||
|
|
||||||
|
# SConscript files write generated headers into obj/ directories at
|
||||||
|
# parse time — these must exist before scons starts.
|
||||||
|
mkdir -p "$BASEDIR/body/board/obj"
|
||||||
|
mkdir -p "$BASEDIR/panda/board/obj"
|
||||||
@@ -79,9 +79,15 @@ function launch {
|
|||||||
agnos_init
|
agnos_init
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# CLEARPILOT: kill stale error display from previous build/run
|
||||||
|
pkill -f "selfdrive/ui/text" 2>/dev/null
|
||||||
|
|
||||||
# write tmux scrollback to a file
|
# write tmux scrollback to a file
|
||||||
tmux capture-pane -pq -S-1000 > /tmp/launch_log
|
tmux capture-pane -pq -S-1000 > /tmp/launch_log
|
||||||
|
|
||||||
|
# Preflight: create dirs git can't track
|
||||||
|
source "$DIR/build_preflight.sh"
|
||||||
|
|
||||||
# start manager
|
# start manager
|
||||||
cd selfdrive/manager
|
cd selfdrive/manager
|
||||||
if [ ! -f $DIR/prebuilt ]; then
|
if [ ! -f $DIR/prebuilt ]; then
|
||||||
|
|||||||
@@ -1,5 +1,38 @@
|
|||||||
#!/usr/bin/bash
|
#!/usr/bin/bash
|
||||||
|
|
||||||
|
# Kill other instances of this script, launch chain, and all managed processes
|
||||||
|
for pid in $(pgrep -f 'launch_openpilot.sh' | grep -v $$); do
|
||||||
|
kill -9 "$pid" 2>/dev/null
|
||||||
|
done
|
||||||
|
for pid in $(pgrep -f 'launch_chffrplus.sh' | grep -v $$); do
|
||||||
|
kill -9 "$pid" 2>/dev/null
|
||||||
|
done
|
||||||
|
pkill -9 -f 'python.*manager.py' 2>/dev/null
|
||||||
|
# Kill all processes started by the manager (run as comma user, in openpilot tree)
|
||||||
|
pkill -9 -f 'selfdrive\.' 2>/dev/null
|
||||||
|
pkill -9 -f 'system\.' 2>/dev/null
|
||||||
|
pkill -9 -f './ui' 2>/dev/null
|
||||||
|
pkill -9 -f 'selfdrive/ui/text' 2>/dev/null
|
||||||
|
sleep 1
|
||||||
|
|
||||||
|
# CLEARPILOT: ensure params persistence dir is owned by comma:comma. Editing
|
||||||
|
# the tree as root leaves files owned by root in /data/params/d_tmp/, and
|
||||||
|
# Params writes done as comma will then EACCES on rename. Reset on every
|
||||||
|
# launch so this never silently breaks again.
|
||||||
|
sudo chown -R comma:comma /data/params
|
||||||
|
|
||||||
bash /data/openpilot/system/clearpilot/on_start.sh
|
bash /data/openpilot/system/clearpilot/on_start.sh
|
||||||
|
|
||||||
|
# CLEARPILOT: start VPN monitor (kills previous instances, runs as root)
|
||||||
|
sudo bash -c 'nohup /data/openpilot/system/clearpilot/vpn-monitor.sh >> /tmp/vpn-monitor.log 2>&1 &'
|
||||||
|
|
||||||
|
# CLEARPILOT: start nice monitor (keeps claude at nice 19)
|
||||||
|
sudo bash -c 'nohup /data/openpilot/system/clearpilot/nice-monitor.sh > /dev/null 2>&1 &'
|
||||||
|
|
||||||
|
# CLEARPILOT: pass --bench flag through to manager via env var
|
||||||
|
if [ "$1" = "--bench" ]; then
|
||||||
|
export BENCH_MODE=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd /data/openpilot
|
||||||
exec ./launch_chffrplus.sh
|
exec ./launch_chffrplus.sh
|
||||||
|
|||||||
Binary file not shown.
+29
-39
@@ -15,48 +15,24 @@
|
|||||||
#include "selfdrive/ui/qt/qt_window.h"
|
#include "selfdrive/ui/qt/qt_window.h"
|
||||||
#include "selfdrive/ui/qt/util.h"
|
#include "selfdrive/ui/qt/util.h"
|
||||||
|
|
||||||
TrackWidget::TrackWidget(QWidget *parent) : QWidget(parent) {
|
// CLEARPILOT: full-screen boot logo background with progress bar overlay
|
||||||
setAttribute(Qt::WA_OpaquePaintEvent);
|
|
||||||
setFixedSize(spinner_size);
|
|
||||||
|
|
||||||
// pre-compute all the track imgs. make this a gif instead?
|
|
||||||
QPixmap comma_img = loadPixmap("../assets/img_spinner_comma.png", spinner_size);
|
|
||||||
QPixmap track_img = loadPixmap("../assets/img_spinner_track.png", spinner_size);
|
|
||||||
|
|
||||||
QTransform transform(1, 0, 0, 1, width() / 2, height() / 2);
|
|
||||||
QPixmap pm(spinner_size);
|
|
||||||
QPainter p(&pm);
|
|
||||||
p.setRenderHint(QPainter::SmoothPixmapTransform);
|
|
||||||
for (int i = 0; i < track_imgs.size(); ++i) {
|
|
||||||
p.resetTransform();
|
|
||||||
p.fillRect(0, 0, spinner_size.width(), spinner_size.height(), Qt::black);
|
|
||||||
p.drawPixmap(0, 0, comma_img);
|
|
||||||
p.setTransform(transform.rotate(360 / spinner_fps));
|
|
||||||
p.drawPixmap(-width() / 2, -height() / 2, track_img);
|
|
||||||
track_imgs[i] = pm.copy();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_anim.setDuration(1000);
|
|
||||||
m_anim.setStartValue(0);
|
|
||||||
m_anim.setEndValue(int(track_imgs.size() -1));
|
|
||||||
m_anim.setLoopCount(-1);
|
|
||||||
m_anim.start();
|
|
||||||
connect(&m_anim, SIGNAL(valueChanged(QVariant)), SLOT(update()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void TrackWidget::paintEvent(QPaintEvent *event) {
|
|
||||||
QPainter painter(this);
|
|
||||||
painter.drawPixmap(0, 0, track_imgs[m_anim.currentValue().toInt()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Spinner
|
|
||||||
|
|
||||||
Spinner::Spinner(QWidget *parent) : QWidget(parent) {
|
Spinner::Spinner(QWidget *parent) : QWidget(parent) {
|
||||||
|
// Load boot logo as full-screen background, rotated 90° CCW
|
||||||
|
// (bg.jpg is pre-rotated 90° CW for the raw framebuffer)
|
||||||
|
QPixmap boot_logo("/usr/comma/bg.jpg");
|
||||||
|
if (!boot_logo.isNull()) {
|
||||||
|
QTransform rot;
|
||||||
|
rot.rotate(-90);
|
||||||
|
bg_img = boot_logo.transformed(rot);
|
||||||
|
}
|
||||||
|
|
||||||
QGridLayout *main_layout = new QGridLayout(this);
|
QGridLayout *main_layout = new QGridLayout(this);
|
||||||
main_layout->setSpacing(0);
|
main_layout->setSpacing(0);
|
||||||
main_layout->setMargin(200);
|
main_layout->setMargin(0);
|
||||||
|
|
||||||
main_layout->addWidget(new TrackWidget(this), 0, 0, Qt::AlignHCenter | Qt::AlignVCenter);
|
// Spacer to push progress bar toward bottom
|
||||||
|
main_layout->setRowStretch(0, 1);
|
||||||
|
|
||||||
text = new QLabel();
|
text = new QLabel();
|
||||||
text->setWordWrap(true);
|
text->setWordWrap(true);
|
||||||
@@ -69,7 +45,10 @@ Spinner::Spinner(QWidget *parent) : QWidget(parent) {
|
|||||||
progress_bar->setTextVisible(false);
|
progress_bar->setTextVisible(false);
|
||||||
progress_bar->setVisible(false);
|
progress_bar->setVisible(false);
|
||||||
progress_bar->setFixedHeight(20);
|
progress_bar->setFixedHeight(20);
|
||||||
main_layout->addWidget(progress_bar, 1, 0, Qt::AlignHCenter);
|
main_layout->addWidget(progress_bar, 2, 0, Qt::AlignHCenter | Qt::AlignBottom);
|
||||||
|
|
||||||
|
// Bottom margin for progress bar
|
||||||
|
main_layout->setContentsMargins(0, 0, 0, 80);
|
||||||
|
|
||||||
setStyleSheet(R"(
|
setStyleSheet(R"(
|
||||||
Spinner {
|
Spinner {
|
||||||
@@ -88,7 +67,7 @@ Spinner::Spinner(QWidget *parent) : QWidget(parent) {
|
|||||||
}
|
}
|
||||||
QProgressBar::chunk {
|
QProgressBar::chunk {
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
background-color: rgba(23, 134, 68, 255);
|
background-color: white;
|
||||||
}
|
}
|
||||||
)");
|
)");
|
||||||
|
|
||||||
@@ -96,6 +75,17 @@ Spinner::Spinner(QWidget *parent) : QWidget(parent) {
|
|||||||
QObject::connect(notifier, &QSocketNotifier::activated, this, &Spinner::update);
|
QObject::connect(notifier, &QSocketNotifier::activated, this, &Spinner::update);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Spinner::paintEvent(QPaintEvent *event) {
|
||||||
|
QPainter p(this);
|
||||||
|
p.fillRect(rect(), Qt::black);
|
||||||
|
if (!bg_img.isNull()) {
|
||||||
|
QPixmap scaled = bg_img.scaled(size(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||||
|
int x = (width() - scaled.width()) / 2;
|
||||||
|
int y = (height() - scaled.height()) / 2;
|
||||||
|
p.drawPixmap(x, y, scaled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Spinner::update(int n) {
|
void Spinner::update(int n) {
|
||||||
std::string line;
|
std::string line;
|
||||||
std::getline(std::cin, line);
|
std::getline(std::cin, line);
|
||||||
|
|||||||
@@ -1,36 +1,23 @@
|
|||||||
#include <array>
|
|
||||||
|
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QPixmap>
|
#include <QPixmap>
|
||||||
#include <QProgressBar>
|
#include <QProgressBar>
|
||||||
#include <QSocketNotifier>
|
#include <QSocketNotifier>
|
||||||
#include <QVariantAnimation>
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
constexpr int spinner_fps = 30;
|
|
||||||
constexpr QSize spinner_size = QSize(360, 360);
|
|
||||||
|
|
||||||
class TrackWidget : public QWidget {
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
TrackWidget(QWidget *parent = nullptr);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void paintEvent(QPaintEvent *event) override;
|
|
||||||
std::array<QPixmap, spinner_fps> track_imgs;
|
|
||||||
QVariantAnimation m_anim;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Spinner : public QWidget {
|
class Spinner : public QWidget {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Spinner(QWidget *parent = 0);
|
explicit Spinner(QWidget *parent = 0);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void paintEvent(QPaintEvent *event) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QLabel *text;
|
QLabel *text;
|
||||||
QProgressBar *progress_bar;
|
QProgressBar *progress_bar;
|
||||||
QSocketNotifier *notifier;
|
QSocketNotifier *notifier;
|
||||||
|
QPixmap bg_img;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void update(int n);
|
void update(int n);
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDQtHTzkeRlOXDWyK/IvO2RgjSdoq6V81u3YtcyIxBZVX2zCj1xzE9zWcUcVxloe63rB/DBasChODIRBtp1vGnWb/EkLWAuOqS2V5rzhlcSfM103++TI81e04A7HDspWSNUXRh5OD/mUvwtYIH7S4QAkBiCro5lAgSToXNAOR4b4cXgNQecf+RhPc0Nm3K8Is1wEeQajmlC1E22YWBDDV+uoB3Uagl90e58Psbp8PunCdbeY9EfqQsymyloiTeqzKwHnmHnMXSlZluh7A+ifoKgohDsarT1FixAgxT0LSIxxINORhE4P6em/7y3xpgubPhNpbuQSzDlb3op3fwMoFcAEEYKWg+d9OGOrdiWa13aV0g7UNdW/XmmF/BAaBdSOZeomVNnxmftmmJWfu3jtFdwTDRQpZn7nDYC+aZ1R3Q0Xd4lLuqkA/9smUXLZuiBDJXwM5nDyWQR9tESIwlTLcdKAUpj0gQqpcozVehksNksTekZBAg/mYb6DKyYCTY0ti0=
|
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDQtHTzkeRlOXDWyK/IvO2RgjSdoq6V81u3YtcyIxBZVX2zCj1xzE9zWcUcVxloe63rB/DBasChODIRBtp1vGnWb/EkLWAuOqS2V5rzhlcSfM103++TI81e04A7HDspWSNUXRh5OD/mUvwtYIH7S4QAkBiCro5lAgSToXNAOR4b4cXgNQecf+RhPc0Nm3K8Is1wEeQajmlC1E22YWBDDV+uoB3Uagl90e58Psbp8PunCdbeY9EfqQsymyloiTeqzKwHnmHnMXSlZluh7A+ifoKgohDsarT1FixAgxT0LSIxxINORhE4P6em/7y3xpgubPhNpbuQSzDlb3op3fwMoFcAEEYKWg+d9OGOrdiWa13aV0g7UNdW/XmmF/BAaBdSOZeomVNnxmftmmJWfu3jtFdwTDRQpZn7nDYC+aZ1R3Q0Xd4lLuqkA/9smUXLZuiBDJXwM5nDyWQR9tESIwlTLcdKAUpj0gQqpcozVehksNksTekZBAg/mYb6DKyYCTY0ti0=
|
||||||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCm/Vq50kqf94allqGq9luBGjDh2Do/rOCA719CRlDOErCvdY+ZaYNumQZ5AbFfU5KcPZwirJLBvhEoH/G0lEAg9TUaUgH/VvqBBztlpcmA1eplZHzEFLnTDn0oO4Tk46bXwjL0anOZfNaUGhbaO4Th7m+9+o16WUduEabPiyVbnqD6P44CANsvBJNKlyUDBzsdkE9z5gULp06i1+JqqXiGV81HoFWZe5YCFv4j4QUPvfmFhcBHViVrOFs87hS4Eu0gWNxQmQBhh6R1ZbjaBlGdE5GyDZQZwlofjfuO06e0HvCDuIAELSYqlGFCmUhlM/LZ6YkF79/HFrg5sS3gsuY5
|
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCm/Vq50kqf94allqGq9luBGjDh2Do/rOCA719CRlDOErCvdY+ZaYNumQZ5AbFfU5KcPZwirJLBvhEoH/G0lEAg9TUaUgH/VvqBBztlpcmA1eplZHzEFLnTDn0oO4Tk46bXwjL0anOZfNaUGhbaO4Th7m+9+o16WUduEabPiyVbnqD6P44CANsvBJNKlyUDBzsdkE9z5gULp06i1+JqqXiGV81HoFWZe5YCFv4j4QUPvfmFhcBHViVrOFs87hS4Eu0gWNxQmQBhh6R1ZbjaBlGdE5GyDZQZwlofjfuO06e0HvCDuIAELSYqlGFCmUhlM/LZ6YkF79/HFrg5sS3gsuY5
|
||||||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHbrOZrByUb2Ci21DdJkhWv/4Bz4oghL9joraQYFq4Om
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHbrOZrByUb2Ci21DdJkhWv/4Bz4oghL9joraQYFq4Om
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOkbLtbZ6jRwmvYiAtXDp7JZ+IBVJIrxY3ZPJ93aQCha root@concordia
|
||||||
|
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCWTdewQ+jCUj9+ZJfte5h0meZhXayd7owIGyXHV0ELCeRAyQrurBPsdTTr7QhcugVuibI+Tr8L3BNuCN8nID5DH+BFAUejulGyMEmQ4Vh22p6Nt0niJHkfiJ2stfayPqe3qGRScVCcY3TpQqlzjyBWOvtwI9/118Gq/lKsjN7DYVwVMHhe1Yzh4SDHOKpsnmDfguRvCSzsg3ZeR1AduaqqM2y0sLZ09Cjpj/vJC/QQ2q2EWtzfmQPejFtjdbqvgoDEQ1OttD5dBgwCMOTPmPMmJ5ns6YJ4L+bi6hynO4/xn3efSHS2mSC6ACwiD/LtTMpsjbUVQsJ4pM/5GY08UoIdnH7P1N+6DA/hah+KAJe8U3WznT6OSXdwWXnYyV+hx4VHBz+/3MnbB1CwtoZoJDnQVpnT3IxBK+pnLHzZJh/g+bFrFbbAC50MRDsoV8nbYvHG3HJQ5GvK96S5NvllGTC/6zo/39ARvfrGtK/2NgNU+NZRjNN67cXjgcUIRdu6eJs= root@concordia
|
||||||
|
|||||||
@@ -1,17 +1,19 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
dongle_id=$(cat /data/params/d/DongleId)
|
# Uses hardware serial as identity check and encryption key
|
||||||
if [[ ! $dongle_id == 90bb71* ]]; then
|
serial=$(sed 's/.*androidboot.serialno=\([^ ]*\).*/\1/' /proc/cmdline)
|
||||||
|
if [[ $serial != 3889765b ]]; then
|
||||||
|
echo "Wrong device (serial=$serial)"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Encrypt SSH keys if source files exist using the custom encrypt tool
|
# Encrypt SSH keys if source files exist using the custom encrypt tool
|
||||||
if [ -f /data/openpilot/system/clearpilot/dev/id_rsa.pub ]; then
|
if [ -f /data/openpilot/system/clearpilot/dev/id_ed25519.pub ]; then
|
||||||
bash /data/openpilot/system/clearpilot/tools/encrypt /data/openpilot/system/clearpilot/dev/id_rsa.pub /data/openpilot/system/clearpilot/dev/id_rsa.pub.cpt
|
bash /data/openpilot/system/clearpilot/tools/encrypt /data/openpilot/system/clearpilot/dev/id_ed25519.pub /data/openpilot/system/clearpilot/dev/id_ed25519.pub.cpt
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -f /data/openpilot/system/clearpilot/dev/id_rsa ]; then
|
if [ -f /data/openpilot/system/clearpilot/dev/id_ed25519 ]; then
|
||||||
bash /data/openpilot/system/clearpilot/tools/encrypt /data/openpilot/system/clearpilot/dev/id_rsa /data/openpilot/system/clearpilot/dev/id_rsa.cpt
|
bash /data/openpilot/system/clearpilot/tools/encrypt /data/openpilot/system/clearpilot/dev/id_ed25519 /data/openpilot/system/clearpilot/dev/id_ed25519.cpt
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -f /data/openpilot/system/clearpilot/dev/reverse_ssh ]; then
|
if [ -f /data/openpilot/system/clearpilot/dev/reverse_ssh ]; then
|
||||||
|
|||||||
Binary file not shown.
@@ -0,0 +1,2 @@
|
|||||||
|
•í-À‘-j¦ñqã A†3ä"|}ôÚÁñžš.\ñ`þQ¥¶ßA^´Ð×~LìbýÊ ÞÔm!Òzï[®�Wí(¯«rýfo¼À˜¦Miê[&ÄoúÏV=�ˆQ�"2�A“i8ÐpÀ"Á!þ1“æ–G:š4ïá<-Ý
|
||||||
|
#
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# tmp for debugging
|
|
||||||
date >> /tmp/dongles
|
|
||||||
echo check dongle >> /tmp/dongles
|
|
||||||
cat /data/params/d/DongleId >> /tmp/dongles
|
|
||||||
echo done >> /tmp/dongles
|
|
||||||
|
|
||||||
dongle_id=$(cat /data/params/d/DongleId)
|
|
||||||
if [[ ! $dongle_id == 90bb71* ]]; then
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo Bringing up brian dev environment
|
|
||||||
|
|
||||||
bash /data/openpilot/system/clearpilot/dev/provision.sh
|
|
||||||
bash /data/openpilot/system/clearpilot/dev/on_start_brian.sh
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
•Í’T4üoŠd¿á¹³€å–³!qús^§‘1E�Œ½—ðÓÉQ¯Åe|0b.7ša|Þ¶$Âï)x‰ ÷9‘Sü8BÌQÛ÷øÃ;TÝ`~?Q!hj2ÔŒwqô/[´ Xðt¬Ç5‡ü,«Ë�ñm¾^v�¯$vf‚ÇH°)J½A
|
|
||||||
²W°n`<@’‹.¬ç&>�&}m8˜‰àÃ;½\$^`Aª›Œ
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Provision script for BrianBot
|
|
||||||
# These actions only occur on BrianBot's comma device.
|
|
||||||
|
|
||||||
# 1. Check the string in /data/params/d/DongleId
|
|
||||||
dongle_id=$(cat /data/params/d/DongleId)
|
|
||||||
if [[ ! $dongle_id == 90bb71* ]]; then
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "BrianBot dongle ID detected."
|
|
||||||
|
|
||||||
# 2. Check if ccrypt is installed, install if not
|
|
||||||
if ! command -v ccrypt >/dev/null 2>&1; then
|
|
||||||
echo "Installing ccrypt..."
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install -y ccrypt
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 3. Decrypt SSH keys if they have not been decrypted yet
|
|
||||||
if [ ! -f /data/openpilot/system/clearpilot/dev/id_rsa.pub ]; then
|
|
||||||
echo "Decrypting SSH keys..."
|
|
||||||
bash /data/openpilot/system/clearpilot/tools/decrypt /data/openpilot/system/clearpilot/dev/id_rsa.pub.cpt /data/openpilot/system/clearpilot/dev/id_rsa.pub
|
|
||||||
bash /data/openpilot/system/clearpilot/tools/decrypt /data/openpilot/system/clearpilot/dev/id_rsa.cpt /data/openpilot/system/clearpilot/dev/id_rsa
|
|
||||||
bash /data/openpilot/system/clearpilot/tools/decrypt /data/openpilot/system/clearpilot/dev/on_start_brian.sh.cpt /data/openpilot/system/clearpilot/dev/on_start_brian.sh
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 4. Ensure .ssh directory and keys exist
|
|
||||||
ssh_dir="/data/ssh/.ssh"
|
|
||||||
if [[ ! -f "$ssh_dir/id_rsa" || ! -f "$ssh_dir/id_rsa.pub" ]]; then
|
|
||||||
echo "Setting up SSH directory and keys..."
|
|
||||||
mkdir -p "$ssh_dir"
|
|
||||||
cp /data/openpilot/system/clearpilot/dev/id_rsa /data/openpilot/system/clearpilot/dev/id_rsa.pub "$ssh_dir"
|
|
||||||
chmod 700 "$ssh_dir"
|
|
||||||
chmod 600 "$ssh_dir/id_rsa" "$ssh_dir/id_rsa.pub"
|
|
||||||
echo hansonxyz > /data/params/d/GithubUsername
|
|
||||||
cat /data/openpilot/system/clearpilot/dev/GithubSshKeys > /data/params/d/GithubSshKeys
|
|
||||||
echo 1 > /data/params/d/SshEnabled
|
|
||||||
sudo systemctl restart ssh
|
|
||||||
cd /data/openpilot
|
|
||||||
git remote remove origin
|
|
||||||
git remote add origin git@privategit.hanson.xyz:brianhansonxyz/clearpilot.git
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Script execution complete."
|
|
||||||
|
|
||||||
|
|
||||||
Executable
+19
@@ -0,0 +1,19 @@
|
|||||||
|
#!/usr/bin/bash
|
||||||
|
|
||||||
|
# Nice monitor — ensures claude processes run at lowest CPU priority.
|
||||||
|
# Checks every 30 seconds and renices any claude process not already at nice 19.
|
||||||
|
|
||||||
|
# Kill other instances of this script
|
||||||
|
for pid in $(pgrep -f 'nice-monitor.sh' | grep -v $$); do
|
||||||
|
kill "$pid" 2>/dev/null
|
||||||
|
done
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
for pid in $(pgrep -f 'claude' 2>/dev/null); do
|
||||||
|
cur=$(awk '{print $19}' /proc/$pid/stat 2>/dev/null)
|
||||||
|
if [ -n "$cur" ] && [ "$cur" != "19" ]; then
|
||||||
|
renice 19 -p "$pid" > /dev/null 2>&1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
sleep 30
|
||||||
|
done
|
||||||
@@ -3,5 +3,45 @@
|
|||||||
# Install logo
|
# Install logo
|
||||||
bash /data/openpilot/system/clearpilot/startup_logo/set_logo.sh
|
bash /data/openpilot/system/clearpilot/startup_logo/set_logo.sh
|
||||||
|
|
||||||
# Reverse ssh if brianbot dongle id
|
# SSH — always, unconditionally, first thing
|
||||||
bash /data/openpilot/system/clearpilot/dev/on_start.sh
|
cat /data/openpilot/system/clearpilot/dev/GithubSshKeys > /data/params/d/GithubSshKeys
|
||||||
|
echo -n 1 > /data/params/d/SshEnabled
|
||||||
|
sudo systemctl enable ssh 2>/dev/null
|
||||||
|
sudo systemctl start ssh
|
||||||
|
|
||||||
|
# Decrypt and install SSH identity keys for root (git auth)
|
||||||
|
serial=$(sed 's/.*androidboot.serialno=\([^ ]*\).*/\1/' /proc/cmdline)
|
||||||
|
ssh_dir="/root/.ssh"
|
||||||
|
if [[ $serial == 3889765b ]] && [[ ! -f "$ssh_dir/id_ed25519" || ! -f "$ssh_dir/id_ed25519.pub" ]]; then
|
||||||
|
echo "Decrypting SSH identity keys for root (serial=$serial)..."
|
||||||
|
tmpdir=$(mktemp -d)
|
||||||
|
bash /data/openpilot/system/clearpilot/tools/decrypt /data/openpilot/system/clearpilot/dev/id_ed25519.cpt "$tmpdir/id_ed25519"
|
||||||
|
bash /data/openpilot/system/clearpilot/tools/decrypt /data/openpilot/system/clearpilot/dev/id_ed25519.pub.cpt "$tmpdir/id_ed25519.pub"
|
||||||
|
sudo mkdir -p "$ssh_dir"
|
||||||
|
sudo cp "$tmpdir/id_ed25519" "$tmpdir/id_ed25519.pub" "$ssh_dir/"
|
||||||
|
rm -rf "$tmpdir"
|
||||||
|
sudo chmod 700 "$ssh_dir"
|
||||||
|
sudo chmod 600 "$ssh_dir/id_ed25519"
|
||||||
|
sudo chmod 644 "$ssh_dir/id_ed25519.pub"
|
||||||
|
echo "SSH identity keys installed to $ssh_dir"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Ensure root SSH config has git.hanson.xyz entry
|
||||||
|
if ! grep -q "Host git.hanson.xyz" "$ssh_dir/config" 2>/dev/null; then
|
||||||
|
sudo tee -a "$ssh_dir/config" > /dev/null <<'SSHCFG'
|
||||||
|
|
||||||
|
Host git.hanson.xyz
|
||||||
|
IdentityFile /root/.ssh/id_ed25519
|
||||||
|
StrictHostKeyChecking no
|
||||||
|
SSHCFG
|
||||||
|
sudo chmod 600 "$ssh_dir/config"
|
||||||
|
echo "SSH config updated for git.hanson.xyz"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Always ensure WiFi radio is on
|
||||||
|
nmcli radio wifi on 2>/dev/null
|
||||||
|
|
||||||
|
# Provision (packages, git pull, build) if no quick_boot flag
|
||||||
|
if [ ! -f /data/quick_boot ]; then
|
||||||
|
sudo bash /data/openpilot/system/clearpilot/provision.sh
|
||||||
|
fi
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# ClearPilot provision script
|
||||||
|
# Runs on first boot (no /data/quick_boot) when internet is available.
|
||||||
|
# Installs packages, pulls latest code, and builds.
|
||||||
|
# SSH is handled by on_start.sh before this runs.
|
||||||
|
# Output is displayed on screen via qt_shell.
|
||||||
|
|
||||||
|
mount -o rw,remount /
|
||||||
|
|
||||||
|
# 1. Wait for internet connectivity
|
||||||
|
echo "Waiting for internet connectivity (up to 30s)..."
|
||||||
|
ONLINE=0
|
||||||
|
for i in $(seq 1 30); do
|
||||||
|
if nmcli networking connectivity check 2>/dev/null | grep -q "full"; then
|
||||||
|
echo "Online after ${i}s"
|
||||||
|
ONLINE=1
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$ONLINE" -eq 0 ]; then
|
||||||
|
echo "No internet after 30s, skipping packages and updates"
|
||||||
|
sleep 3
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 3. Install packages
|
||||||
|
echo "Remounting / read-write..."
|
||||||
|
sudo mount -o remount,rw /
|
||||||
|
echo "Installing packages..."
|
||||||
|
sudo apt-get update -qq
|
||||||
|
sudo apt-get install -y openvpn curl ccrypt
|
||||||
|
#echo "Installing Node.js 20..."
|
||||||
|
#curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
|
||||||
|
sudo apt-get install -y nodejs
|
||||||
|
mount -o rw,remount /
|
||||||
|
echo "Installing Claude Code..."
|
||||||
|
curl -fsSL https://claude.ai/install.sh | bash
|
||||||
|
cat > /usr/local/bin/claude <<'WRAPPER'
|
||||||
|
#!/bin/bash
|
||||||
|
sudo mount -o rw,remount /
|
||||||
|
exec /root/.local/bin/claude "$@"
|
||||||
|
WRAPPER
|
||||||
|
chmod +x /usr/local/bin/claude
|
||||||
|
echo "Packages installed"
|
||||||
|
# 4. Ensure git remote uses SSH (not HTTPS)
|
||||||
|
cd /data/openpilot
|
||||||
|
EXPECTED_REMOTE="git@git.hanson.xyz:brianhansonxyz/clearpilot.git"
|
||||||
|
CURRENT_REMOTE=$(git remote get-url origin 2>/dev/null)
|
||||||
|
if [ "$CURRENT_REMOTE" != "$EXPECTED_REMOTE" ]; then
|
||||||
|
echo "Fixing git remote: $CURRENT_REMOTE -> $EXPECTED_REMOTE"
|
||||||
|
git remote set-url origin "$EXPECTED_REMOTE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 5. Pull latest from remote (remote always wins)
|
||||||
|
echo "Checking for updates..."
|
||||||
|
git fetch origin clearpilot
|
||||||
|
LOCAL=$(git rev-parse HEAD)
|
||||||
|
REMOTE=$(git rev-parse origin/clearpilot)
|
||||||
|
if [ "$LOCAL" != "$REMOTE" ]; then
|
||||||
|
echo "Updating: $(git log --oneline -1 HEAD) -> $(git log --oneline -1 origin/clearpilot)"
|
||||||
|
git reset --hard origin/clearpilot
|
||||||
|
sudo chown -R comma:comma /data/openpilot
|
||||||
|
echo "Update complete"
|
||||||
|
else
|
||||||
|
echo "Already up to date"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 5. Build
|
||||||
|
echo ""
|
||||||
|
sudo chown -R comma:comma /data/openpilot
|
||||||
|
touch /data/quick_boot
|
||||||
|
|
||||||
|
echo "Provision complete"
|
||||||
|
sleep 2
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
exec bash /data/openpilot/system/clearpilot/provision.sh 2>&1
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
@@ -3,8 +3,9 @@
|
|||||||
# Create a 2160x1080 true color bitmap canvas with black background
|
# Create a 2160x1080 true color bitmap canvas with black background
|
||||||
convert -size 2160x1080 canvas:black /tmp/black_canvas.png
|
convert -size 2160x1080 canvas:black /tmp/black_canvas.png
|
||||||
|
|
||||||
# Place the image in the center of the canvas, blending the transparent background
|
# Scale logo 140% then center on canvas
|
||||||
composite -gravity center /data/openpilot/selfdrive/clearpilot/theme/clearpilot/images/boot_logo.png /tmp/black_canvas.png /tmp/centered_image.png
|
convert /data/openpilot/selfdrive/clearpilot/theme/clearpilot/images/boot_logo.png -resize 140% /tmp/scaled_logo.png
|
||||||
|
composite -gravity center /tmp/scaled_logo.png /tmp/black_canvas.png /tmp/centered_image.png
|
||||||
|
|
||||||
# Rotate the image clockwise 90 degrees
|
# Rotate the image clockwise 90 degrees
|
||||||
convert /tmp/centered_image.png -rotate 90 /tmp/rotated_image.png
|
convert /tmp/centered_image.png -rotate 90 /tmp/rotated_image.png
|
||||||
@@ -13,4 +14,4 @@ convert /tmp/centered_image.png -rotate 90 /tmp/rotated_image.png
|
|||||||
convert /tmp/rotated_image.png -quality 95 /data/openpilot/system/clearpilot/startup_logo/bg.jpg
|
convert /tmp/rotated_image.png -quality 95 /data/openpilot/system/clearpilot/startup_logo/bg.jpg
|
||||||
|
|
||||||
# Clean up temporary files
|
# Clean up temporary files
|
||||||
rm /tmp/black_canvas.png /tmp/centered_image.png /tmp/rotated_image.png
|
rm /tmp/black_canvas.png /tmp/scaled_logo.png /tmp/centered_image.png /tmp/rotated_image.png
|
||||||
|
|||||||
@@ -3,6 +3,13 @@
|
|||||||
set -x
|
set -x
|
||||||
|
|
||||||
|
|
||||||
|
# CLEARPILOT: regenerate bg.jpg if boot_logo.png is newer (handles logo changes)
|
||||||
|
BOOT_LOGO="/data/openpilot/selfdrive/clearpilot/theme/clearpilot/images/boot_logo.png"
|
||||||
|
GENERATED_BG="/data/openpilot/system/clearpilot/startup_logo/bg.jpg"
|
||||||
|
if [ "$BOOT_LOGO" -nt "$GENERATED_BG" ] 2>/dev/null; then
|
||||||
|
bash /data/openpilot/system/clearpilot/startup_logo/generate_logo.sh
|
||||||
|
fi
|
||||||
|
|
||||||
# Check if md5sum of /usr/comma/bg.jpg is not equal to md5sum of /data/openpilot/system/clearpilot/startup_logo/bg.jpg
|
# Check if md5sum of /usr/comma/bg.jpg is not equal to md5sum of /data/openpilot/system/clearpilot/startup_logo/bg.jpg
|
||||||
if [ "$(md5sum /usr/comma/bg.jpg | awk '{print $1}')" != "$(md5sum /data/openpilot/system/clearpilot/startup_logo/bg.jpg | awk '{print $1}')" ]; then
|
if [ "$(md5sum /usr/comma/bg.jpg | awk '{print $1}')" != "$(md5sum /data/openpilot/system/clearpilot/startup_logo/bg.jpg | awk '{print $1}')" ]; then
|
||||||
bash /data/openpilot/system/clearpilot/startup_logo/generate_logo.sh
|
bash /data/openpilot/system/clearpilot/startup_logo/generate_logo.sh
|
||||||
|
|||||||
@@ -10,8 +10,11 @@ fi
|
|||||||
src="$1"
|
src="$1"
|
||||||
dest="$2"
|
dest="$2"
|
||||||
|
|
||||||
# Read DongleId for decryption key
|
# Use hardware serial as decryption key
|
||||||
dongle_id=/data/params/d/DongleId
|
serial=$(sed 's/.*androidboot.serialno=\([^ ]*\).*/\1/' /proc/cmdline)
|
||||||
|
keyfile=$(mktemp)
|
||||||
|
echo -n "$serial" > "$keyfile"
|
||||||
|
|
||||||
# Decrypt the file
|
# Decrypt the file
|
||||||
cat "$src" | ccrypt -d -k "$dongle_id" > "$dest"
|
cat "$src" | ccrypt -d -k "$keyfile" > "$dest"
|
||||||
|
rm -f "$keyfile"
|
||||||
|
|||||||
@@ -10,8 +10,11 @@ fi
|
|||||||
src="$1"
|
src="$1"
|
||||||
dest="$2"
|
dest="$2"
|
||||||
|
|
||||||
# Read DongleId for encryption key
|
# Use hardware serial as encryption key
|
||||||
dongle_id=/data/params/d/DongleId
|
serial=$(sed 's/.*androidboot.serialno=\([^ ]*\).*/\1/' /proc/cmdline)
|
||||||
|
keyfile=$(mktemp)
|
||||||
|
echo -n "$serial" > "$keyfile"
|
||||||
|
|
||||||
# Encrypt the file
|
# Encrypt the file
|
||||||
cat "$src" | ccrypt -e -k "$dongle_id" > "$dest"
|
cat "$src" | ccrypt -e -k "$keyfile" > "$dest"
|
||||||
|
rm -f "$keyfile"
|
||||||
|
|||||||
Executable
+153
@@ -0,0 +1,153 @@
|
|||||||
|
#!/usr/bin/bash
|
||||||
|
|
||||||
|
# VPN monitor — connects OpenVPN when internet is up, disconnects when down.
|
||||||
|
# Drops and reconnects when WiFi SSID changes (stale tunnel prevention).
|
||||||
|
# On non-home networks, resolves VPN hostname via 8.8.8.8 and passes IP directly.
|
||||||
|
# Keepalive: pings gateway through tunnel, two failures 10s apart = reconnect.
|
||||||
|
# SIGTERM: gracefully stops tunnel and exits.
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
CONF="$SCRIPT_DIR/vpn.ovpn"
|
||||||
|
VPN_HOST="vpn.hanson.xyz"
|
||||||
|
VPN_PORT="1194"
|
||||||
|
HOME_SSID="risa"
|
||||||
|
VPN_GW="192.168.69.1"
|
||||||
|
CHECK_HOST="1.1.1.1"
|
||||||
|
INTERVAL=30
|
||||||
|
CONNECT_TIMEOUT=30
|
||||||
|
MAX_FAILURES=3
|
||||||
|
PREV_SSID=""
|
||||||
|
FAIL_COUNT=0
|
||||||
|
ACTIVE_VPN_IP=""
|
||||||
|
|
||||||
|
kill_vpn() {
|
||||||
|
killall openvpn 2>/dev/null
|
||||||
|
# Clean up host route to VPN server
|
||||||
|
if [ -n "$ACTIVE_VPN_IP" ]; then
|
||||||
|
ip route del "$ACTIVE_VPN_IP/32" 2>/dev/null
|
||||||
|
ACTIVE_VPN_IP=""
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
get_default_gw() {
|
||||||
|
ip route show default | awk '/via/ {print $3; exit}'
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve_vpn() {
|
||||||
|
if [ "$CURR_SSID" != "$HOME_SSID" ]; then
|
||||||
|
dig +short @8.8.8.8 "$VPN_HOST" 2>/dev/null | tail -1
|
||||||
|
else
|
||||||
|
dig +short "$VPN_HOST" 2>/dev/null | tail -1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Graceful shutdown on SIGTERM
|
||||||
|
shutdown() {
|
||||||
|
echo "$(date): SIGTERM received, stopping vpn and exiting"
|
||||||
|
kill_vpn
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
trap shutdown SIGTERM SIGINT
|
||||||
|
|
||||||
|
# Kill other instances of this script and wait for graceful shutdown
|
||||||
|
for pid in $(pgrep -f 'vpn-monitor.sh' | grep -v $$); do
|
||||||
|
kill "$pid" 2>/dev/null
|
||||||
|
done
|
||||||
|
sleep 5
|
||||||
|
# Force kill any that didn't exit
|
||||||
|
for pid in $(pgrep -f 'vpn-monitor.sh' | grep -v $$); do
|
||||||
|
kill -9 "$pid" 2>/dev/null
|
||||||
|
done
|
||||||
|
|
||||||
|
# Kill any existing VPN and clean up
|
||||||
|
kill_vpn
|
||||||
|
sleep 1
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
CURR_SSID="$(iwgetid -r 2>/dev/null)"
|
||||||
|
|
||||||
|
# Detect SSID change (only when switching between two known networks)
|
||||||
|
if [ -n "$PREV_SSID" ] && [ -n "$CURR_SSID" ] && [ "$PREV_SSID" != "$CURR_SSID" ]; then
|
||||||
|
echo "$(date): wifi changed from '$PREV_SSID' to '$CURR_SSID', dropping vpn"
|
||||||
|
kill_vpn
|
||||||
|
FAIL_COUNT=0
|
||||||
|
sleep 5
|
||||||
|
fi
|
||||||
|
PREV_SSID="$CURR_SSID"
|
||||||
|
|
||||||
|
if ping -c 1 -W 3 "$CHECK_HOST" > /dev/null 2>&1; then
|
||||||
|
# Internet is up — check tunnel health if connected
|
||||||
|
if ip link show tun0 > /dev/null 2>&1; then
|
||||||
|
# Keepalive: ping gateway through tunnel, two failures 10s apart = dead
|
||||||
|
if ! ping -c 1 -W 3 -I tun0 "$VPN_GW" > /dev/null 2>&1; then
|
||||||
|
sleep 10
|
||||||
|
if ! ping -c 1 -W 3 -I tun0 "$VPN_GW" > /dev/null 2>&1; then
|
||||||
|
echo "$(date): keepalive failed twice, dropping vpn"
|
||||||
|
kill_vpn
|
||||||
|
sleep 5
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Start VPN if not running
|
||||||
|
if ! ip link show tun0 > /dev/null 2>&1; then
|
||||||
|
if [ "$FAIL_COUNT" -ge "$MAX_FAILURES" ]; then
|
||||||
|
# Back off after repeated failures — just wait for next interval
|
||||||
|
sleep "$INTERVAL"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Resolve VPN server IP (via 8.8.8.8 on non-home networks)
|
||||||
|
RESOLVED_IP="$(resolve_vpn)"
|
||||||
|
if [ -z "$RESOLVED_IP" ]; then
|
||||||
|
echo "$(date): failed to resolve $VPN_HOST (ssid=$CURR_SSID)"
|
||||||
|
FAIL_COUNT=$((FAIL_COUNT + 1))
|
||||||
|
sleep "$INTERVAL"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Add host route to VPN server via current default gateway
|
||||||
|
# so VPN traffic survives tun0 coming up
|
||||||
|
GW="$(get_default_gw)"
|
||||||
|
if [ -n "$GW" ]; then
|
||||||
|
ip route replace "$RESOLVED_IP/32" via "$GW"
|
||||||
|
echo "$(date): host route $RESOLVED_IP via $GW"
|
||||||
|
fi
|
||||||
|
ACTIVE_VPN_IP="$RESOLVED_IP"
|
||||||
|
|
||||||
|
echo "$(date): starting openvpn -> $RESOLVED_IP (attempt $((FAIL_COUNT + 1))/$MAX_FAILURES, ssid=$CURR_SSID)"
|
||||||
|
nice -n 19 openvpn --config "$CONF" --remote "$RESOLVED_IP" "$VPN_PORT" --daemon --log-append /tmp/openvpn.log
|
||||||
|
|
||||||
|
# Wait for tunnel to come up
|
||||||
|
CONNECTED=0
|
||||||
|
for i in $(seq 1 "$CONNECT_TIMEOUT"); do
|
||||||
|
if ip link show tun0 > /dev/null 2>&1; then
|
||||||
|
CONNECTED=1
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$CONNECTED" -eq 1 ]; then
|
||||||
|
echo "$(date): vpn connected (took ${i}s)"
|
||||||
|
FAIL_COUNT=0
|
||||||
|
else
|
||||||
|
echo "$(date): vpn failed to connect within ${CONNECT_TIMEOUT}s, killing"
|
||||||
|
kill_vpn
|
||||||
|
FAIL_COUNT=$((FAIL_COUNT + 1))
|
||||||
|
if [ "$FAIL_COUNT" -ge "$MAX_FAILURES" ]; then
|
||||||
|
echo "$(date): $MAX_FAILURES consecutive failures, backing off"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# Internet is down — kill VPN if running
|
||||||
|
if ip link show tun0 > /dev/null 2>&1; then
|
||||||
|
echo "$(date): internet down, stopping openvpn"
|
||||||
|
kill_vpn
|
||||||
|
fi
|
||||||
|
FAIL_COUNT=0
|
||||||
|
fi
|
||||||
|
sleep "$INTERVAL"
|
||||||
|
done
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
client
|
||||||
|
dev tun
|
||||||
|
proto udp
|
||||||
|
remote vpn.hanson.xyz 1194
|
||||||
|
resolv-retry infinite
|
||||||
|
nobind
|
||||||
|
persist-key
|
||||||
|
persist-tun
|
||||||
|
remote-cert-tls server
|
||||||
|
cipher AES-256-GCM
|
||||||
|
auth SHA256
|
||||||
|
verb 3
|
||||||
|
pull-filter ignore "redirect-gateway"
|
||||||
|
# pull-filter ignore "route "
|
||||||
|
|
||||||
|
<ca>
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIB2jCCAX+gAwIBAgIUFVGjbK1Qb5d3RkkoNPMsXeI/xVAwCgYIKoZIzj0EAwIw
|
||||||
|
HjEcMBoGA1UEAwwTT3BlblZQTi1JbnRlcm5hbC1DQTAgFw0yNjAyMDcwODQ3Mzda
|
||||||
|
GA8yMTI2MDExNDA4NDczN1owHjEcMBoGA1UEAwwTT3BlblZQTi1JbnRlcm5hbC1D
|
||||||
|
QTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABGb6RWOFnCJ9t7X5q6fqpv0y3Hg/
|
||||||
|
dTU3ky+MAjfPRYfUWfiM7wVKubYOCc+pUHsJXWaghqu7nQoCeSzVDcPXlWGjgZgw
|
||||||
|
gZUwDAYDVR0TBAUwAwEB/zAdBgNVHQ4EFgQUNThAWabF1zsqNE19iCKuZMjHBIUw
|
||||||
|
WQYDVR0jBFIwUIAUNThAWabF1zsqNE19iCKuZMjHBIWhIqQgMB4xHDAaBgNVBAMM
|
||||||
|
E09wZW5WUE4tSW50ZXJuYWwtQ0GCFBVRo2ytUG+Xd0ZJKDTzLF3iP8VQMAsGA1Ud
|
||||||
|
DwQEAwIBBjAKBggqhkjOPQQDAgNJADBGAiEA2mPwEK8G4HXlRu6WZVSRdqyCPYYd
|
||||||
|
KffYalCXgw3pZ/sCIQC9qPNckHtubycu8kq4iM8Vl1vYMVEorn7DUFdXJCvtcg==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
</ca>
|
||||||
|
|
||||||
|
<cert>
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIB2TCCAYCgAwIBAgIRALuRBSB68/ccWM8SASfEIV0wCgYIKoZIzj0EAwIwHjEc
|
||||||
|
MBoGA1UEAwwTT3BlblZQTi1JbnRlcm5hbC1DQTAgFw0yNjA0MTIwMDA1NDhaGA8y
|
||||||
|
MTI2MDMxOTAwMDU0OFowEDEOMAwGA1UEAwwFY29tbWEwWTATBgcqhkjOPQIBBggq
|
||||||
|
hkjOPQMBBwNCAAQ/jN83Z2Ikk+IWVPGxN0CNFCh74Yrb3W6VXAjGWa+ppVxSbdeq
|
||||||
|
YVBWjJl6qSg6n2ZMDivQ5NcKgsxMcY9ly/LEo4GqMIGnMAkGA1UdEwQCMAAwHQYD
|
||||||
|
VR0OBBYEFDIulLc8hAwTkGHq+z8K8eBBM0vVMFkGA1UdIwRSMFCAFDU4QFmmxdc7
|
||||||
|
KjRNfYgirmTIxwSFoSKkIDAeMRwwGgYDVQQDDBNPcGVuVlBOLUludGVybmFsLUNB
|
||||||
|
ghQVUaNsrVBvl3dGSSg08yxd4j/FUDATBgNVHSUEDDAKBggrBgEFBQcDAjALBgNV
|
||||||
|
HQ8EBAMCB4AwCgYIKoZIzj0EAwIDRwAwRAIgR/ssLDNLmt1s0WXwGLszBUrlstUu
|
||||||
|
9nhP2PcmdnsOit4CIECFbQ7RHEZLQJWsL2DvKowCCzDtA6ZGDILTVfHwNyDn
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
</cert>
|
||||||
|
|
||||||
|
<key>
|
||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgYolghDmo5ISWxjQy
|
||||||
|
sayXuFRSW5fkiIXJ1SGvSRLnmBmhRANCAAQ/jN83Z2Ikk+IWVPGxN0CNFCh74Yrb
|
||||||
|
3W6VXAjGWa+ppVxSbdeqYVBWjJl6qSg6n2ZMDivQ5NcKgsxMcY9ly/LE
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
|
</key>
|
||||||
|
|
||||||
|
<tls-crypt>
|
||||||
|
#
|
||||||
|
# 2048 bit OpenVPN static key
|
||||||
|
#
|
||||||
|
-----BEGIN OpenVPN Static key V1-----
|
||||||
|
5d6fedacbb44013958eef494b179f21d
|
||||||
|
51b158484c08cb125b8ddd2a919ed44f
|
||||||
|
5cae951b1f85f483f0108b1000fac1e6
|
||||||
|
334ab5b2f3c7352c3a53e814e2e4cdc7
|
||||||
|
f401d5eb2e13449539313f18de53563d
|
||||||
|
a72318979c31ef76caad86317064aede
|
||||||
|
940ab3d799886b9667f4deabb8b159c2
|
||||||
|
12bd7f27c91a7bfd3b9a315dbac3391d
|
||||||
|
fb3c354b7955627937fd6163c1683705
|
||||||
|
e46b252ee9c383507b5a4496462f3d67
|
||||||
|
25dc48bbca8170574efa22b3c37c4bcc
|
||||||
|
ad30e92d39aae5326c59a4484302d388
|
||||||
|
7836837bd5098faeda430aa6db69d8df
|
||||||
|
fe62aeed2bef6afb7c0c742fe8644040
|
||||||
|
3c4e46deb3915467c351018592c58545
|
||||||
|
5b5d7b8c204d37104f9848573d8eb73b
|
||||||
|
-----END OpenVPN Static key V1-----
|
||||||
|
</tls-crypt>
|
||||||
Reference in New Issue
Block a user