update at 2026-03-15 14:54:51

This commit is contained in:
douboer@gmail.com
2026-03-15 14:54:51 +08:00
parent c02b23bad2
commit d375f7174f
26 changed files with 1284 additions and 15 deletions

View File

@@ -1,5 +1,7 @@
{ {
"items": [ "items": [
{"name": "Kindle Dashboard", "action": "/mnt/us/dashboard/start.sh"} {"name": "Kindle Dashboard", "action": "/mnt/us/dashboard/start.sh"},
{"name": "Dashboard Debug On", "action": "/mnt/us/dashboard/debug-on.sh"},
{"name": "Dashboard Debug Off", "action": "/mnt/us/dashboard/debug-off.sh"}
] ]
} }

View File

@@ -43,6 +43,16 @@ If you're using KUAL you can use simple extension to start this Dashboard
1. Copy folder `kindle-dash` from `KUAL` folder to the kual `extensions` folder. (located in `/mnt/us/extensions`) 1. Copy folder `kindle-dash` from `KUAL` folder to the kual `extensions` folder. (located in `/mnt/us/extensions`)
## Debugging
For on-device debugging without suspending the Kindle, set `DISABLE_SYSTEM_SUSPEND=true` in `local/env.sh`.
The dashboard loop will keep running and use a normal `sleep` between refreshes instead of writing to `/sys/power/state`.
If you're connected over SSH you can also run `DEBUG=true ./start.sh` to keep the process in the foreground with shell tracing enabled.
If you're launching from KUAL, use `Dashboard Debug On` before a normal start to persistently disable suspend in `local/env.sh`, and `Dashboard Debug Off` when you want to restore the normal low-power behavior.
Both actions stop the current dashboard process so the new setting takes effect on the next start.
If you're connected over SSH and only want a one-off foreground session, you can still run `/mnt/us/dashboard/start-debug.sh`.
## How this works ## How this works
* This code periodically downloads a dashboard image from an HTTP(s) endpoint. * This code periodically downloads a dashboard image from an HTTP(s) endpoint.
@@ -53,6 +63,7 @@ If you're using KUAL you can use simple extension to start this Dashboard
* The releases contain a pre-compiled binary of the [ht](https://github.com/ducaale/ht) command-line HTTP client. This fully supports modern HTTPS crypto, wheras the built-in `curl` and `wget` commands don't (because they rely on a very old `openssl` library). * The releases contain a pre-compiled binary of the [ht](https://github.com/ducaale/ht) command-line HTTP client. This fully supports modern HTTPS crypto, wheras the built-in `curl` and `wget` commands don't (because they rely on a very old `openssl` library).
* For a detailed Kindle Voyage 5.13.6 jailbreak and deployment walkthrough, see [docs/kindle-voyage-5.13.6-watchthis-zh.md](./docs/kindle-voyage-5.13.6-watchthis-zh.md). * For a detailed Kindle Voyage 5.13.6 jailbreak and deployment walkthrough, see [docs/kindle-voyage-5.13.6-watchthis-zh.md](./docs/kindle-voyage-5.13.6-watchthis-zh.md).
* For a detailed same-device dashboard/SSH troubleshooting playbook based on the 2026-03-15 session, see [docs/kindle-voyage-5.13.6-dual-ssh-playbook-zh.md](./docs/kindle-voyage-5.13.6-dual-ssh-playbook-zh.md).
## Credits ## Credits

View File

@@ -0,0 +1,412 @@
# Kindle Voyage 5.13.6 Dashboard/SSH 一次成操作手册
本文基于 2026-03-15 的一次实机排障整理,目标是让下次同型号 Kindle 在安装 dashboard、开启调试、打通 SSH 时尽量一次完成,不再重复今天这 5 个小时的试错过程。
## 适用范围
- Kindle Voyage
- 固件 5.13.6
- 已完成越狱
- 已安装 KUAL
- 通过 MRPI 安装扩展
- 目标项目为本仓库 `dash/`
## 最终结论
今天最终打通的稳定路径不是 USB 直连 SSH而是
1. Kindle 本机先通过 KTerm 拉起 `dropbear`
2.`dropbear` 监听 `*:22`
3. 从 Mac 通过 Kindle 的 Wi-Fi 地址登录
4. 使用 `~/.ssh/id_ed25519_git` 这把 key
最终验证通过的登录方式:
```sh
ssh -i ~/.ssh/id_ed25519_git root@192.168.72.3
```
后续为了简化操作,已在本机 [~/.ssh/config](/Users/gavin/.ssh/config) 中加入:
```sshconfig
Host kindle
HostName 192.168.72.3
User root
IdentityFile ~/.ssh/id_ed25519_git
IdentitiesOnly yes
PreferredAuthentications publickey
PasswordAuthentication no
KbdInteractiveAuthentication no
```
所以当前可直接:
```sh
ssh kindle
```
## 下次同型号设备的推荐顺序
### 1. 路由器和网络先处理
先确认这几项:
- Kindle 和 Mac 在同一个主 Wi-Fi
- 不是 Guest Wi-Fi
- ASUS Lyra Trio 中 `禁止无线用户互通` 为关闭
这一步的意义是先保证 Mac 能访问 Kindle 的 Wi-Fi 地址。今天前期大量时间都浪费在这里。
注意:
- Kindle 有时不回 `ping`
- 但这不等于 SSH 不通
- 真正应检查的是 `arp``nc -vz <ip> 22``ssh`
### 2. Kindle 端必装内容
建议固定安装:
- KUAL
- USBNetwork
- KTerm
- 本仓库 dashboard 文件
其中:
- USBNetwork 用于提供 `usbnet` 和调试工具
- KTerm 是本地 root shell是真正的兜底入口
今天的结论是:
一旦外部 SSH 不通,不要继续盲猜,直接进 KTerm 才是最快路线。
### 3. Dashboard 调试先关闭自动挂起
调试 dashboard 时,先在 KUAL 中执行:
1. `Dashboard Debug On`
2. `Kindle Dashboard`
调试结束后再执行:
1. `Dashboard Debug Off`
2. `Kindle Dashboard`
相关脚本:
- [dash/src/debug-on.sh](/Users/gavin/kindle-dash/dash/src/debug-on.sh)
- [dash/src/debug-off.sh](/Users/gavin/kindle-dash/dash/src/debug-off.sh)
- [dash/src/start-debug.sh](/Users/gavin/kindle-dash/dash/src/start-debug.sh)
- [dash/KUAL/kindle-dash/menu.json](/Users/gavin/kindle-dash/dash/KUAL/kindle-dash/menu.json)
核心经验:
- 调试时不要让设备自动 suspend
- 否则 KUAL 很容易刚打开就被挂起打断
## 今天确认过的关键事实
### 1. KUAL 的 `sshd up/down` 不是最终真相
今天多次出现:
- KUAL 显示 `sshd up`
- 但设备本机并没有 `sshd``dropbear` 进程
所以后续一律以本机 shell 为准:
```sh
/mnt/us/usbnet/bin/lsof -n -P -iTCP:22
ps -ef | grep -E 'sshd|dropbear'
```
### 2. `169.254.148.176` 不是 Kindle 的 USBNetwork 地址
这是今天最关键的坑之一。
我们最后确认:
- `169.254.148.176` 是 Mac 自己 USB 网卡的链路本地地址
- Kindle 在 `usbnet` 模式下的真实 USB IP 是 `192.168.15.244`
这个值来自当天在 Kindle 本机采集到的 `collect.log`
```text
usb0 inet addr:192.168.15.244
```
以及 `usbnet` 配置:
```sh
KINDLE_IP=192.168.15.244
```
也就是说:
- 之前对 `169.254.148.176` 的 SSH 测试,实际上是在连 Mac 自己那块接口
- 这就是为什么前面很多现象互相矛盾
### 3. USBNetwork 直连链路没有最终打通
即使:
- Mac 端给 `en8`/`en11` 配了 `192.168.15.201/24`
- Kindle 端 `dropbear` 看起来监听了 `*:22`
最终 ARP 仍然不通,表现为:
- `arp``192.168.15.244``incomplete`
- `nc -vz 192.168.15.244 22` 超时
所以这次真正可用的 SSH 入口,不是 USB 直连,而是 Wi-Fi。
### 4. 真正成功的是 Wi-Fi 上的 DropBear
最终确认:
- Wi-Fi IP 是 `192.168.72.3`
- 服务端 banner 是 `dropbear_2020.81`
- 成功接受的密钥是 `~/.ssh/id_ed25519_git`
验证结果:
- `nc -vz 192.168.72.3 22` 成功
- `ssh -i ~/.ssh/id_ed25519_git root@192.168.72.3 true` 成功
- 可拿到 `uid=0(root)`
### 5. 设备实际跑的是手工拉起的 DropBear
最终有效进程不是系统默认那份 OpenSSH而是我们在 Kindle 本机手工拉起的:
```sh
bin/dropbearmulti dropbear -F -E -p 22 -P /mnt/us/usbnet/run/dropbear-force-22.pid -n
```
其中:
- `-p 22` 监听 22 端口
- `-n` 是这个 Kindle hack 里的“禁用密码检查”开关
`dropbear -h` 已实机确认:
```text
-n Disable password checking (/!\ Kindle hack, don't use this!)
```
## 一次成的推荐操作
### A. 第一次准备
1. 越狱
2. 安装 KUAL
3. 安装 USBNetwork
4. 安装 KTerm
5. 同步 dashboard 到 `/mnt/us/dashboard`
6. 同步 KUAL 菜单到 `/mnt/us/extensions/kindle-dash`
### B. Dashboard 调试
1. KUAL -> `Dashboard Debug On`
2. KUAL -> `Kindle Dashboard`
3. 调试完成后再 `Dashboard Debug Off`
### C. SSH 启动的最短稳定路线
如果外部 SSH 一开始就不通,不要继续折腾 USB。
先把仓库里的 Kindle 辅助脚本复制到设备根目录:
```sh
scp /Users/gavin/kindle-dash/scripts/kindle/*.sh kindle:/mnt/us/
```
如果这时还没有 `ssh kindle`,也可以先通过 USB 存储模式手动拷到 `/mnt/us/`
然后在 Kindle 本机的 KTerm 里执行:
```sh
sh /mnt/us/ssh-force-dropbear-22.sh
/mnt/us/usbnet/bin/lsof -n -P -iTCP:22
```
必须看到类似:
```text
dropbear... TCP *:22 (LISTEN)
```
然后从 Mac 走 Wi-Fi 登录:
```sh
ssh -i ~/.ssh/id_ed25519_git root@192.168.72.3
```
或:
```sh
ssh kindle
```
### D. 登录成功后验证
登录后执行:
```sh
id
uname -a
ps -ef | grep -E 'sshd|dropbear|telnetd' | grep -v grep
```
应至少看到:
- `uid=0(root)`
- `dropbearmulti dropbear ... -p 22 ...`
## 今天踩过的坑
### 1. 不要一开始就把重点放在 USB 直连 SSH
USBNetwork 的确安装了,但:
- USBMS 和 USBNetwork 是互斥的
- USB 侧 IP 容易看错
- Mac 侧可能出现多个候选接口
- 接口名、ARP、链路状态都容易误判
所以:
- USB 更适合拷文件
- 真正稳定的远程入口优先走 Wi-Fi SSH
### 2. 不要相信 `ping` 单独判断
今天实际情况是:
- 某些阶段 `ping` 不通
-`ssh` 可以通
所以后续统一使用:
```sh
nc -vz <ip> 22
ssh <host>
```
### 3. 不要把 “出现 Password:” 等同于“密码一定对”
前期出现过:
```text
ssh root@...
Password:
```
这只能说明对端当时有 SSH 在监听。
不代表:
- 这就是正确的那份 SSH 服务
- 配置文件就是你刚改的那份
- 默认密码一定可用
### 4. 本机 shell 才是最终裁判
如果出现任何矛盾,比如:
- KUAL 说 `sshd up`
- Mac 连不上
- 改过配置却没生效
立即转入 KTerm本机检查
```sh
id
ps -ef
/mnt/us/usbnet/bin/lsof -n -P -iTCP:22
cat /mnt/us/usbnet/etc/config
```
## 今天留下的可复用资产
### 1. Dashboard 调试入口
已在仓库中加入:
- [dash/src/debug-on.sh](/Users/gavin/kindle-dash/dash/src/debug-on.sh)
- [dash/src/debug-off.sh](/Users/gavin/kindle-dash/dash/src/debug-off.sh)
- [dash/src/start-debug.sh](/Users/gavin/kindle-dash/dash/src/start-debug.sh)
- [dash/KUAL/kindle-dash/menu.json](/Users/gavin/kindle-dash/dash/KUAL/kindle-dash/menu.json)
### 2. Mac 侧 USBNetwork 辅助脚本
已在仓库中加入:
- [scripts/connect-kindle-usbnet-mac.sh](/Users/gavin/kindle-dash/scripts/connect-kindle-usbnet-mac.sh)
### 3. Kindle 侧 SSH 救援脚本
已在仓库中加入:
- [scripts/kindle/ssh-collect.sh](/Users/gavin/kindle-dash/scripts/kindle/ssh-collect.sh)
- [scripts/kindle/ssh-fix-all-keys.sh](/Users/gavin/kindle-dash/scripts/kindle/ssh-fix-all-keys.sh)
- [scripts/kindle/ssh-force-openssh-22.sh](/Users/gavin/kindle-dash/scripts/kindle/ssh-force-openssh-22.sh)
- [scripts/kindle/ssh-force-dropbear-22.sh](/Users/gavin/kindle-dash/scripts/kindle/ssh-force-dropbear-22.sh)
- [scripts/kindle/ssh-stop-all.sh](/Users/gavin/kindle-dash/scripts/kindle/ssh-stop-all.sh)
推荐复制方式:
```sh
scp /Users/gavin/kindle-dash/scripts/kindle/*.sh kindle:/mnt/us/
```
作用:
- 自动尝试 `en8``en11`
- 给候选接口加 `192.168.15.201/24`
- 探测 `192.168.15.244:22`
- 如果 USB 链路能通,再继续尝试 SSH
这次虽然最终证明 USB 不是稳定入口,但这个脚本保留着仍有价值。
## 建议的下次标准流程
下次同型号设备,推荐严格按下面顺序:
1. 先关掉路由器无线隔离,确保 Kindle 和 Mac 在同一主 Wi-Fi。
2. 先把 dashboard 的 `Debug On/Off` 菜单装好。
3. 先装 KTerm不要等 SSH 坏了才找本地终端。
4. 初次调试先用 `Dashboard Debug On`,避免设备自动挂起。
5. SSH 优先目标设为 Wi-Fi不要优先押宝 USB 直连。
6. 外部 SSH 不通时,立即转 KTerm。
7. 在 KTerm 手工拉起 `dropbear` 后,再从 Mac 走 Wi-Fi 登录。
8. 登录成功后再考虑要不要继续优化 USBNetwork 或持久化 SSH 配置。
## 当前最短命令
### Kindle 端
```sh
sh /mnt/us/ssh-force-dropbear-22.sh
```
### Mac 端
```sh
ssh kindle
```
如果 `ssh kindle` 不通,先确认:
- Kindle 还连着 Wi-Fi
- 当前 IP 还是 `192.168.72.3`
- `dropbear` 还在 `*:22` 监听
## 最后一条经验
今天真正节省时间的做法不是“继续猜”,而是尽快把问题缩到:
- 这是网络层问题
- 这是进程问题
- 这是 key 问题
- 还是这是错误 IP 问题
一旦拿到本机 KTerm root shell排障效率会比外部盲试高一个数量级。

View File

@@ -13,6 +13,11 @@
- 节点:`6:2` - 节点:`6:2`
- 链接:`https://www.figma.com/design/3bXFNM5nM6mCq0TpL3nPYK/calendar?node-id=6-2&m=dev` - 链接:`https://www.figma.com/design/3bXFNM5nM6mCq0TpL3nPYK/calendar?node-id=6-2&m=dev`
指针与表盘素材的拆分约束来自 Figma annotation
- 节点:`23:418`
- 链接:`https://www.figma.com/design/3bXFNM5nM6mCq0TpL3nPYK/calendar?node-id=23-418&m=dev`
该节点 annotation 已明确: 该节点 annotation 已明确:
- `阳历当天` - `阳历当天`
@@ -123,9 +128,64 @@
- 分针每分钟一个角度,共 `60` - 分针每分钟一个角度,共 `60`
- 时针如果要做到真正随分钟连续移动,需要 `12 * 60 = 720` - 时针如果要做到真正随分钟连续移动,需要 `12 * 60 = 720`
- 这些都是小尺寸 patch不是整屏图体积可控 - 这些都是小尺寸 patch不是整屏图体积可控
- 所有素材统一放在 Kindle 本地 `assets/` 目录下
推荐目录:
```text
/mnt/us/dashboard/assets/clock-face.png
/mnt/us/dashboard/assets/hour-hand/000.png ... 719.png
/mnt/us/dashboard/assets/minute-hand/00.png ... 59.png
```
如果后续确认 Kindle 端存在稳定的本地绘线工具,再考虑把指针改成算法绘制;当前版本不依赖这个前提。 如果后续确认 Kindle 端存在稳定的本地绘线工具,再考虑把指针改成算法绘制;当前版本不依赖这个前提。
### 3.4 指针锚点与缩放规则
这部分是 Kindle 端渲染能否正确对齐的关键约束,不能省略。
根据 Figma 节点 `23:418` 的 annotation 与素材结构:
- `hour-hand``minute-hand` 的中心位置不是素材端点
- 指针的旋转中心是素材内部的圆点中心
- Kindle 端贴图时,不能把图片底边、顶边或几何中心当作对齐基准
因此,运行时必须遵守下面的规则:
1. 每类指针素材都要记录自己的 `pivot`
2. 渲染时以 `pivot` 对齐表盘中心,而不是以素材端点对齐
3. 指针长度不能写死为某个绝对像素值,而是要随表盘大小同比例缩放
4. `pivot` 偏移量也必须和指针长度一起同比例缩放
也就是说,如果表盘从设计稿尺寸缩到 Kindle 运行时尺寸:
- 时针长度随表盘直径同比例缩放
- 分针长度随表盘直径同比例缩放
- 时针的 `pivot.x / pivot.y` 也按同一比例缩放
- 分针的 `pivot.x / pivot.y` 也按同一比例缩放
推荐缩放公式:
```text
scale = min(runtime_clock_width / design_clock_width, runtime_clock_height / design_clock_height)
rendered_hand_width = source_hand_width * scale
rendered_hand_height = source_hand_height * scale
rendered_pivot_x = source_pivot_x * scale
rendered_pivot_y = source_pivot_y * scale
```
其中:
- `design_clock_width / design_clock_height` 指 Figma 导出该套素材时所对应的基准表盘尺寸
- `runtime_clock_width / runtime_clock_height` 指 Kindle 端最终时钟区域尺寸
这意味着:
- 表盘主体和指针素材必须来自同一套基准设计尺寸
- 不能单独替换某一类不同倍率的指针图,否则时针、分针与刻度会失配
- 如果未来切换到别的机型或别的表盘尺寸,只需要换 `clockRegion``scale`,不需要重做对齐逻辑
## 4. 为什么不能只把表盘放进整页背景 ## 4. 为什么不能只把表盘放进整页背景
这个问题必须单独说明。 这个问题必须单独说明。
@@ -275,14 +335,28 @@ kindle local:
"height": 220 "height": 220
}, },
"clockFace": { "clockFace": {
"path": "clock-face.png", "path": "assets/clock-face.png",
"managedOnKindle": true "managedOnKindle": true,
"designWidth": 220,
"designHeight": 220
}, },
"clockHands": { "clockHands": {
"hourPattern": "assets/hour-hand/%03d.png", "hourPattern": "assets/hour-hand/%03d.png",
"minutePattern": "assets/minute-hand/%02d.png", "minutePattern": "assets/minute-hand/%02d.png",
"refreshIntervalMinutes": 1, "refreshIntervalMinutes": 1,
"networkRequired": false "networkRequired": false,
"anchorMode": "pivot",
"scaleWithClockFace": true,
"hourHand": {
"sourceDesignWidth": 220,
"sourceDesignHeight": 220,
"pivotSource": "figma-annotation-center-dot"
},
"minuteHand": {
"sourceDesignWidth": 220,
"sourceDesignHeight": 220,
"pivotSource": "figma-annotation-center-dot"
}
} }
} }
``` ```
@@ -291,6 +365,8 @@ kindle local:
- `x/y/width/height` 先按设计稿记录 - `x/y/width/height` 先按设计稿记录
- 真正接入 Kindle 时,要换算成最终截图分辨率下的实际像素值 - 真正接入 Kindle 时,要换算成最终截图分辨率下的实际像素值
- `pivotSource` 表示指针锚点来自 Figma 素材内部圆点中心,而不是素材端点
- `scaleWithClockFace=true` 表示运行时必须按表盘尺寸同步缩放指针长度与 `pivot`
## 8. Kindle 侧刷新策略 ## 8. Kindle 侧刷新策略
@@ -332,12 +408,13 @@ MobileRead Wiki 明确写了:
- `hour_index = ((hour % 12) * 60 + minute) = 000..719` - `hour_index = ((hour % 12) * 60 + minute) = 000..719`
3. 在固定坐标先画: 3. 在固定坐标先画:
- `clock-face.png` - `clock-face.png`
4. 再画: 4. 根据当前 `clockRegion` 与素材基准尺寸计算统一缩放比例
5. 以素材内部 `pivot` 对齐表盘中心,先画:
- `hour-hand/<hour_index>.png` - `hour-hand/<hour_index>.png`
5. 再画: 6.以素材内部 `pivot` 对齐表盘中心,画:
- `minute-hand/<minute_index>.png` - `minute-hand/<minute_index>.png`
6. 默认做局部/普通刷新 7. 默认做局部/普通刷新
7.`10``15` 分钟对时钟区域补一次全刷,清理残影 8.`10``15` 分钟对时钟区域补一次全刷,清理残影
### 8.3 功耗模型 ### 8.3 功耗模型
@@ -412,6 +489,8 @@ export CLOCK_FULL_REFRESH_INTERVAL_MINUTES=15
- 产出 `clock-face.png` - 产出 `clock-face.png`
- 产出 `hour-hand``minute-hand` 素材库 - 产出 `hour-hand``minute-hand` 素材库
- 明确每类指针素材的 `pivot` 与基准表盘尺寸
- 确保时针、分针长度能随表盘尺寸同比例缩放适配
输出: 输出:
@@ -443,7 +522,7 @@ export CLOCK_FULL_REFRESH_INTERVAL_MINUTES=15
- 本地 `minute-hand/*.png` - 本地 `minute-hand/*.png`
4. 分钟刷新时: 4. 分钟刷新时:
- 先重画表盘 - 先重画表盘
- 再重画时针 -`pivot + scale` 规则重画时针
- 再重画分针 -`pivot + scale` 规则重画分针
也就是说,**背景是远端低频资源,时钟是本地高频资源,二者不要混在同一个刷新链路里**。 也就是说,**背景是远端低频资源,时钟是本地高频资源,二者不要混在同一个刷新链路里**。

View File

@@ -10,6 +10,7 @@ LOW_BATTERY_CMD="$DIR/local/low-battery.sh"
REFRESH_SCHEDULE=${REFRESH_SCHEDULE:-"2,32 8-17 * * MON-FRI"} REFRESH_SCHEDULE=${REFRESH_SCHEDULE:-"2,32 8-17 * * MON-FRI"}
FULL_DISPLAY_REFRESH_RATE=${FULL_DISPLAY_REFRESH_RATE:-0} FULL_DISPLAY_REFRESH_RATE=${FULL_DISPLAY_REFRESH_RATE:-0}
SLEEP_SCREEN_INTERVAL=${SLEEP_SCREEN_INTERVAL:-3600} SLEEP_SCREEN_INTERVAL=${SLEEP_SCREEN_INTERVAL:-3600}
DISABLE_SYSTEM_SUSPEND=${DISABLE_SYSTEM_SUSPEND:-false}
RTC=/sys/devices/platform/mxc_rtc.0/wakeup_enable RTC=/sys/devices/platform/mxc_rtc.0/wakeup_enable
LOW_BATTERY_REPORTING=${LOW_BATTERY_REPORTING:-false} LOW_BATTERY_REPORTING=${LOW_BATTERY_REPORTING:-false}
@@ -27,6 +28,10 @@ init() {
echo "Starting dashboard with $REFRESH_SCHEDULE refresh..." echo "Starting dashboard with $REFRESH_SCHEDULE refresh..."
if [ "$DISABLE_SYSTEM_SUSPEND" = true ]; then
echo "System suspend disabled, using normal sleep between refreshes."
fi
/etc/init.d/framework stop /etc/init.d/framework stop
initctl stop webreader >/dev/null 2>&1 initctl stop webreader >/dev/null 2>&1
echo powersave >/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor echo powersave >/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
@@ -88,6 +93,9 @@ rtc_sleep() {
if [ "$DEBUG" = true ]; then if [ "$DEBUG" = true ]; then
sleep "$duration" sleep "$duration"
elif [ "$DISABLE_SYSTEM_SUSPEND" = true ]; then
echo "Skipping system suspend, sleeping for ${duration}s instead"
sleep "$duration"
else else
# shellcheck disable=SC2039 # shellcheck disable=SC2039
[ "$(cat "$RTC")" -eq 0 ] && echo -n "$duration" >"$RTC" [ "$(cat "$RTC")" -eq 0 ] && echo -n "$duration" >"$RTC"

41
dash/src/debug-off.sh Executable file
View File

@@ -0,0 +1,41 @@
#!/usr/bin/env sh
# 持久关闭调试模式:修改 env.sh恢复正常的省电挂起行为。
set -eu
DIR="$(dirname "$0")"
ENV_FILE="$DIR/local/env.sh"
TMP_FILE="$DIR/local/env.sh.tmp"
if [ ! -f "$ENV_FILE" ]; then
echo "未找到配置文件:$ENV_FILE"
exit 1
fi
# 只替换目标配置,避免重复追加同一环境变量。
awk '
BEGIN {
updated = 0
}
/^export DISABLE_SYSTEM_SUSPEND=/ {
print "export DISABLE_SYSTEM_SUSPEND=false"
updated = 1
next
}
{
print
}
END {
if (!updated) {
print "export DISABLE_SYSTEM_SUSPEND=false"
}
}
' "$ENV_FILE" > "$TMP_FILE"
mv "$TMP_FILE" "$ENV_FILE"
# 已运行的 dashboard 进程不会重新读取 env.sh切换后先停掉它
# 避免旧进程继续按旧配置运行。
pkill -f "$DIR/dash.sh" 2>/dev/null || true
echo "已关闭 Dashboard 调试模式。当前 Dashboard 已停止,请重新启动 Kindle Dashboard。"

41
dash/src/debug-on.sh Executable file
View File

@@ -0,0 +1,41 @@
#!/usr/bin/env sh
# 持久开启调试模式:修改 env.sh让后续普通启动也不进入系统挂起。
set -eu
DIR="$(dirname "$0")"
ENV_FILE="$DIR/local/env.sh"
TMP_FILE="$DIR/local/env.sh.tmp"
if [ ! -f "$ENV_FILE" ]; then
echo "未找到配置文件:$ENV_FILE"
exit 1
fi
# 只替换目标配置,避免重复追加同一环境变量。
awk '
BEGIN {
updated = 0
}
/^export DISABLE_SYSTEM_SUSPEND=/ {
print "export DISABLE_SYSTEM_SUSPEND=true"
updated = 1
next
}
{
print
}
END {
if (!updated) {
print "export DISABLE_SYSTEM_SUSPEND=true"
}
}
' "$ENV_FILE" > "$TMP_FILE"
mv "$TMP_FILE" "$ENV_FILE"
# 已运行的 dashboard 进程不会重新读取 env.sh切换后先停掉它
# 避免旧进程继续按旧配置进入系统挂起。
pkill -f "$DIR/dash.sh" 2>/dev/null || true
echo "已开启 Dashboard 调试模式。当前 Dashboard 已停止,请重新启动 Kindle Dashboard。"

View File

@@ -13,6 +13,11 @@ export TIMEZONE=${TIMEZONE:-"Asia/Shanghai"}
# 等图片尺寸与刷新逻辑确认无误后,再改回 4 之类的值以节省功耗。 # 等图片尺寸与刷新逻辑确认无误后,再改回 4 之类的值以节省功耗。
export FULL_DISPLAY_REFRESH_RATE=${FULL_DISPLAY_REFRESH_RATE:-0} export FULL_DISPLAY_REFRESH_RATE=${FULL_DISPLAY_REFRESH_RATE:-0}
# 调试开关:设为 true 后,主循环仍会按计划拉图和刷新屏幕,
# 但不会把 Kindle 写入 /sys/power/state 进入系统挂起。
# 适合通过 KUAL 或普通 start.sh 连续观察效果,调试结束后再改回 false。
export DISABLE_SYSTEM_SUSPEND=${DISABLE_SYSTEM_SUSPEND:-false}
# When the time until the next wakeup is greater or equal to this number, # When the time until the next wakeup is greater or equal to this number,
# the dashboard will not be refreshed anymore, but instead show a # the dashboard will not be refreshed anymore, but instead show a
# 'kindle is sleeping' screen. This can be useful if your schedule only runs # 'kindle is sleeping' screen. This can be useful if your schedule only runs

8
dash/src/start-debug.sh Executable file
View File

@@ -0,0 +1,8 @@
#!/usr/bin/env sh
# 调试启动脚本:强制关闭系统挂起,便于在 Kindle 上持续观察刷新效果。
DIR="$(dirname "$0")"
export DISABLE_SYSTEM_SUSPEND=true
exec "$DIR/start.sh"

View File

@@ -0,0 +1,41 @@
#!/usr/bin/env sh
# 持久关闭调试模式:修改 env.sh恢复正常的省电挂起行为。
set -eu
DIR="$(dirname "$0")"
ENV_FILE="$DIR/local/env.sh"
TMP_FILE="$DIR/local/env.sh.tmp"
if [ ! -f "$ENV_FILE" ]; then
echo "未找到配置文件:$ENV_FILE"
exit 1
fi
# 只替换目标配置,避免重复追加同一环境变量。
awk '
BEGIN {
updated = 0
}
/^export DISABLE_SYSTEM_SUSPEND=/ {
print "export DISABLE_SYSTEM_SUSPEND=false"
updated = 1
next
}
{
print
}
END {
if (!updated) {
print "export DISABLE_SYSTEM_SUSPEND=false"
}
}
' "$ENV_FILE" > "$TMP_FILE"
mv "$TMP_FILE" "$ENV_FILE"
# 已运行的 dashboard 进程不会重新读取 env.sh切换后先停掉它
# 避免旧进程继续按旧配置运行。
pkill -f "$DIR/dash.sh" 2>/dev/null || true
echo "已关闭 Dashboard 调试模式。当前 Dashboard 已停止,请重新启动 Kindle Dashboard。"

View File

@@ -0,0 +1,41 @@
#!/usr/bin/env sh
# 持久开启调试模式:修改 env.sh让后续普通启动也不进入系统挂起。
set -eu
DIR="$(dirname "$0")"
ENV_FILE="$DIR/local/env.sh"
TMP_FILE="$DIR/local/env.sh.tmp"
if [ ! -f "$ENV_FILE" ]; then
echo "未找到配置文件:$ENV_FILE"
exit 1
fi
# 只替换目标配置,避免重复追加同一环境变量。
awk '
BEGIN {
updated = 0
}
/^export DISABLE_SYSTEM_SUSPEND=/ {
print "export DISABLE_SYSTEM_SUSPEND=true"
updated = 1
next
}
{
print
}
END {
if (!updated) {
print "export DISABLE_SYSTEM_SUSPEND=true"
}
}
' "$ENV_FILE" > "$TMP_FILE"
mv "$TMP_FILE" "$ENV_FILE"
# 已运行的 dashboard 进程不会重新读取 env.sh切换后先停掉它
# 避免旧进程继续按旧配置进入系统挂起。
pkill -f "$DIR/dash.sh" 2>/dev/null || true
echo "已开启 Dashboard 调试模式。当前 Dashboard 已停止,请重新启动 Kindle Dashboard。"

View File

@@ -0,0 +1,8 @@
#!/usr/bin/env sh
# 调试启动脚本:强制关闭系统挂起,便于在 Kindle 上持续观察刷新效果。
DIR="$(dirname "$0")"
export DISABLE_SYSTEM_SUSPEND=true
exec "$DIR/start.sh"

View File

@@ -1,5 +1,7 @@
{ {
"items": [ "items": [
{"name": "Kindle Dashboard", "action": "/mnt/us/dashboard/start.sh"} {"name": "Kindle Dashboard", "action": "/mnt/us/dashboard/start.sh"},
{"name": "Dashboard Debug On", "action": "/mnt/us/dashboard/debug-on.sh"},
{"name": "Dashboard Debug Off", "action": "/mnt/us/dashboard/debug-off.sh"}
] ]
} }

View File

@@ -0,0 +1,41 @@
#!/usr/bin/env sh
# 持久关闭调试模式:修改 env.sh恢复正常的省电挂起行为。
set -eu
DIR="$(dirname "$0")"
ENV_FILE="$DIR/local/env.sh"
TMP_FILE="$DIR/local/env.sh.tmp"
if [ ! -f "$ENV_FILE" ]; then
echo "未找到配置文件:$ENV_FILE"
exit 1
fi
# 只替换目标配置,避免重复追加同一环境变量。
awk '
BEGIN {
updated = 0
}
/^export DISABLE_SYSTEM_SUSPEND=/ {
print "export DISABLE_SYSTEM_SUSPEND=false"
updated = 1
next
}
{
print
}
END {
if (!updated) {
print "export DISABLE_SYSTEM_SUSPEND=false"
}
}
' "$ENV_FILE" > "$TMP_FILE"
mv "$TMP_FILE" "$ENV_FILE"
# 已运行的 dashboard 进程不会重新读取 env.sh切换后先停掉它
# 避免旧进程继续按旧配置运行。
pkill -f "$DIR/dash.sh" 2>/dev/null || true
echo "已关闭 Dashboard 调试模式。当前 Dashboard 已停止,请重新启动 Kindle Dashboard。"

View File

@@ -0,0 +1,41 @@
#!/usr/bin/env sh
# 持久开启调试模式:修改 env.sh让后续普通启动也不进入系统挂起。
set -eu
DIR="$(dirname "$0")"
ENV_FILE="$DIR/local/env.sh"
TMP_FILE="$DIR/local/env.sh.tmp"
if [ ! -f "$ENV_FILE" ]; then
echo "未找到配置文件:$ENV_FILE"
exit 1
fi
# 只替换目标配置,避免重复追加同一环境变量。
awk '
BEGIN {
updated = 0
}
/^export DISABLE_SYSTEM_SUSPEND=/ {
print "export DISABLE_SYSTEM_SUSPEND=true"
updated = 1
next
}
{
print
}
END {
if (!updated) {
print "export DISABLE_SYSTEM_SUSPEND=true"
}
}
' "$ENV_FILE" > "$TMP_FILE"
mv "$TMP_FILE" "$ENV_FILE"
# 已运行的 dashboard 进程不会重新读取 env.sh切换后先停掉它
# 避免旧进程继续按旧配置进入系统挂起。
pkill -f "$DIR/dash.sh" 2>/dev/null || true
echo "已开启 Dashboard 调试模式。当前 Dashboard 已停止,请重新启动 Kindle Dashboard。"

View File

@@ -0,0 +1,8 @@
#!/usr/bin/env sh
# 调试启动脚本:强制关闭系统挂起,便于在 Kindle 上持续观察刷新效果。
DIR="$(dirname "$0")"
export DISABLE_SYSTEM_SUSPEND=true
exec "$DIR/start.sh"

View File

@@ -0,0 +1,41 @@
#!/usr/bin/env sh
# 持久关闭调试模式:修改 env.sh恢复正常的省电挂起行为。
set -eu
DIR="$(dirname "$0")"
ENV_FILE="$DIR/local/env.sh"
TMP_FILE="$DIR/local/env.sh.tmp"
if [ ! -f "$ENV_FILE" ]; then
echo "未找到配置文件:$ENV_FILE"
exit 1
fi
# 只替换目标配置,避免重复追加同一环境变量。
awk '
BEGIN {
updated = 0
}
/^export DISABLE_SYSTEM_SUSPEND=/ {
print "export DISABLE_SYSTEM_SUSPEND=false"
updated = 1
next
}
{
print
}
END {
if (!updated) {
print "export DISABLE_SYSTEM_SUSPEND=false"
}
}
' "$ENV_FILE" > "$TMP_FILE"
mv "$TMP_FILE" "$ENV_FILE"
# 已运行的 dashboard 进程不会重新读取 env.sh切换后先停掉它
# 避免旧进程继续按旧配置运行。
pkill -f "$DIR/dash.sh" 2>/dev/null || true
echo "已关闭 Dashboard 调试模式。当前 Dashboard 已停止,请重新启动 Kindle Dashboard。"

View File

@@ -0,0 +1,41 @@
#!/usr/bin/env sh
# 持久开启调试模式:修改 env.sh让后续普通启动也不进入系统挂起。
set -eu
DIR="$(dirname "$0")"
ENV_FILE="$DIR/local/env.sh"
TMP_FILE="$DIR/local/env.sh.tmp"
if [ ! -f "$ENV_FILE" ]; then
echo "未找到配置文件:$ENV_FILE"
exit 1
fi
# 只替换目标配置,避免重复追加同一环境变量。
awk '
BEGIN {
updated = 0
}
/^export DISABLE_SYSTEM_SUSPEND=/ {
print "export DISABLE_SYSTEM_SUSPEND=true"
updated = 1
next
}
{
print
}
END {
if (!updated) {
print "export DISABLE_SYSTEM_SUSPEND=true"
}
}
' "$ENV_FILE" > "$TMP_FILE"
mv "$TMP_FILE" "$ENV_FILE"
# 已运行的 dashboard 进程不会重新读取 env.sh切换后先停掉它
# 避免旧进程继续按旧配置进入系统挂起。
pkill -f "$DIR/dash.sh" 2>/dev/null || true
echo "已开启 Dashboard 调试模式。当前 Dashboard 已停止,请重新启动 Kindle Dashboard。"

View File

@@ -0,0 +1,8 @@
#!/usr/bin/env sh
# 调试启动脚本:强制关闭系统挂起,便于在 Kindle 上持续观察刷新效果。
DIR="$(dirname "$0")"
export DISABLE_SYSTEM_SUSPEND=true
exec "$DIR/start.sh"

View File

@@ -1,5 +1,7 @@
{ {
"items": [ "items": [
{"name": "Kindle Dashboard", "action": "/mnt/us/dashboard/start.sh"} {"name": "Kindle Dashboard", "action": "/mnt/us/dashboard/start.sh"},
{"name": "Dashboard Debug On", "action": "/mnt/us/dashboard/debug-on.sh"},
{"name": "Dashboard Debug Off", "action": "/mnt/us/dashboard/debug-off.sh"}
] ]
} }

View File

@@ -0,0 +1,128 @@
#!/bin/sh
set -eu
# 这个脚本用于在 Mac 上给 Kindle 的 USBNetwork 网卡补一个 192.168.15.x 地址,
# 然后立刻验证 22 端口和 SSH 公钥登录是否可用。
#
# 默认值适配当前这台 Kindle
# - Kindle USB IP: 192.168.15.244
# - 本机别名 IP: 192.168.15.201
# - 默认网卡: en8
#
# 用法:
# sh scripts/connect-kindle-usbnet-mac.sh
# sh scripts/connect-kindle-usbnet-mac.sh auto 192.168.15.244 192.168.15.201
# sh scripts/connect-kindle-usbnet-mac.sh en8 192.168.15.244 192.168.15.201
#
# 参数说明:
# $1: Mac 上的 USB 网卡名,默认 auto自动尝试 en8/en11
# $2: Kindle 在 usbnet 模式下的 IP默认 192.168.15.244
# $3: Mac 要补的别名 IP默认 192.168.15.201
USB_IFACE="${1:-auto}"
KINDLE_IP="${2:-192.168.15.244}"
HOST_IP="${3:-192.168.15.201}"
KEY1="${HOME}/.ssh/id_ed25519"
KEY2="${HOME}/.ssh/id_ed25519_git"
pick_iface() {
if [ "${USB_IFACE}" != "auto" ]; then
echo "${USB_IFACE}"
return 0
fi
# 当前这台 Mac 在 Kindle 插入后会出现多个活动的 USB 相关接口,
# 实测常见候选是 en8 和 en11。这里按顺序轮询哪个能打通 22 端口就用哪个。
for iface in en8 en11; do
if ! ifconfig "${iface}" >/dev/null 2>&1; then
continue
fi
echo >&2
echo "== 尝试接口 ${iface} ==" >&2
sudo ifconfig "${iface}" inet "${HOST_IP}" netmask 255.255.255.0 alias >/dev/null 2>&1 || true
sudo arp -d "${KINDLE_IP}" >/dev/null 2>&1 || true
echo "当前网卡状态:" >&2
ifconfig "${iface}" >&2
echo >&2
echo "路由检查:" >&2
route -n get "${KINDLE_IP}" >&2 || true
echo >&2
echo "22 端口探测:" >&2
if nc -vz -G 5 "${KINDLE_IP}" 22; then
echo "${iface}"
return 0
fi
echo "接口 ${iface} 未打通,清理别名后继续尝试下一个。" >&2
sudo ifconfig "${iface}" -alias "${HOST_IP}" >/dev/null 2>&1 || true
done
return 1
}
echo "== 配置 USB 网卡 =="
echo "接口参数: ${USB_IFACE}"
echo "Kindle IP: ${KINDLE_IP}"
echo "本机别名 IP: ${HOST_IP}"
FOUND_IFACE="$(pick_iface)" || {
echo
echo "未能在候选 USB 网卡上打通 ${KINDLE_IP}:22。"
echo "通常说明 Kindle 端的 sshd/dropbear 没有在跑,或者 USBNetwork 链路本身还没真正连起来。"
exit 1
}
USB_IFACE="${FOUND_IFACE}"
echo
echo "== 选中的接口 =="
echo "${USB_IFACE}"
echo
echo "== 尝试使用第一把密钥登录 =="
if [ -f "${KEY1}" ]; then
if ssh -i "${KEY1}" \
-o BatchMode=yes \
-o IdentitiesOnly=yes \
-o StrictHostKeyChecking=no \
-o UserKnownHostsFile=/tmp/kindle_usbnet_known_hosts_1 \
root@"${KINDLE_IP}" true; then
echo "第一把密钥验证成功,进入交互登录。"
exec ssh -i "${KEY1}" \
-o IdentitiesOnly=yes \
-o StrictHostKeyChecking=no \
-o UserKnownHostsFile=/tmp/kindle_usbnet_known_hosts_1 \
root@"${KINDLE_IP}"
fi
else
echo "未找到密钥: ${KEY1}"
fi
echo
echo "== 尝试使用第二把密钥登录 =="
if [ -f "${KEY2}" ]; then
if ssh -i "${KEY2}" \
-o BatchMode=yes \
-o IdentitiesOnly=yes \
-o StrictHostKeyChecking=no \
-o UserKnownHostsFile=/tmp/kindle_usbnet_known_hosts_2 \
root@"${KINDLE_IP}" true; then
echo "第二把密钥验证成功,进入交互登录。"
exec ssh -i "${KEY2}" \
-o IdentitiesOnly=yes \
-o StrictHostKeyChecking=no \
-o UserKnownHostsFile=/tmp/kindle_usbnet_known_hosts_2 \
root@"${KINDLE_IP}"
fi
else
echo "未找到密钥: ${KEY2}"
fi
echo "两把密钥都未登录成功。"
exit 1

View File

@@ -0,0 +1,87 @@
#!/bin/sh
set -eu
# 采集 Kindle 当前 SSH、网络、进程、配置等诊断信息。
# 输出目录会落在 /mnt/us/ssh-debug/<时间戳>/collect.log。
TS="$(date +%Y%m%d-%H%M%S 2>/dev/null || echo now)"
OUT_DIR="/mnt/us/ssh-debug/${TS}"
LOG_FILE="${OUT_DIR}/collect.log"
mkdir -p "${OUT_DIR}"
exec >"${LOG_FILE}" 2>&1
echo "=== BASIC ==="
date 2>/dev/null || true
id 2>/dev/null || true
uname -a 2>/dev/null || true
echo "HOME=${HOME:-}"
echo
echo "=== ROOT PASSWD ENTRY ==="
grep '^root:' /etc/passwd 2>/dev/null || true
echo
echo "=== SSH BINARIES ==="
ls -l /usr/sbin/sshd /mnt/us/usbnet/sbin/sshd /usr/bin/dropbear /mnt/us/usbnet/bin/dropbearmulti 2>/dev/null || true
echo
echo "=== PROCESS LIST ==="
ps -ef 2>/dev/null || ps 2>/dev/null || true
echo
echo "=== LSOF TCP:22 ==="
if [ -x /mnt/us/usbnet/bin/lsof ]; then
/mnt/us/usbnet/bin/lsof -n -P -iTCP:22 2>/dev/null || true
fi
echo
echo "=== LSOF ALL TCP LISTENERS ==="
if [ -x /mnt/us/usbnet/bin/lsof ]; then
/mnt/us/usbnet/bin/lsof -n -P -iTCP -sTCP:LISTEN 2>/dev/null || true
fi
echo
echo "=== /PROC/NET/TCP ==="
cat /proc/net/tcp 2>/dev/null || true
cat /proc/net/tcp6 2>/dev/null || true
echo
echo "=== NETWORK ==="
ifconfig -a 2>/dev/null || ifconfig 2>/dev/null || true
route -n 2>/dev/null || netstat -rn 2>/dev/null || true
echo
echo "=== IPTABLES ==="
iptables -S 2>/dev/null || true
echo
echo "=== USBNET RUN DIR ==="
ls -la /mnt/us/usbnet/run 2>/dev/null || true
echo
echo "=== USBNET CONFIG FILES ==="
for f in /mnt/us/usbnet/etc/config /mnt/us/usbnet/etc/sshd_config /mnt/us/usbnet/etc/authorized_keys; do
echo "--- ${f} ---"
sed -n '1,200p' "${f}" 2>/dev/null || true
done
echo
echo "=== SYSTEM SSHD -T ==="
/usr/sbin/sshd -T 2>&1 || true
echo
echo "=== USBNET SSHD -T ==="
/mnt/us/usbnet/sbin/sshd -T -f /mnt/us/usbnet/etc/sshd_config 2>&1 || true
echo
echo "=== COMMON SSH DIRS ==="
for d in /root/.ssh /var/local/root/.ssh "${HOME:-/root}/.ssh" /mnt/us/usbnet/etc/dot.ssh; do
echo "--- ${d} ---"
ls -la "${d}" 2>/dev/null || true
done
echo
echo "=== DONE ==="
echo "${OUT_DIR}"

View File

@@ -0,0 +1,38 @@
#!/bin/sh
set -eu
# 把 usbnet 共用的 authorized_keys 同步到几处常见 root SSH 目录,
# 避免不同 sshd/dropbear 读取路径不一致。
TS="$(date +%Y%m%d-%H%M%S 2>/dev/null || echo now)"
OUT_DIR="/mnt/us/ssh-debug/${TS}"
LOG_FILE="${OUT_DIR}/fix-all-keys.log"
SOURCE_KEYS="/mnt/us/usbnet/etc/authorized_keys"
mkdir -p "${OUT_DIR}"
exec >"${LOG_FILE}" 2>&1
ROOT_HOME="$(awk -F: '/^root:/{print $6}' /etc/passwd 2>/dev/null || true)"
[ -n "${ROOT_HOME}" ] || ROOT_HOME="/tmp/root"
echo "Root home: ${ROOT_HOME}"
echo "Source keys: ${SOURCE_KEYS}"
for target_dir in "${ROOT_HOME}/.ssh" /root/.ssh /var/local/root/.ssh /mnt/us/usbnet/etc/dot.ssh; do
echo "--- target: ${target_dir} ---"
mkdir -p "${target_dir}"
if [ -f "${target_dir}/authorized_keys" ]; then
cp "${target_dir}/authorized_keys" "${target_dir}/authorized_keys.bak.${TS}" || true
fi
cp "${SOURCE_KEYS}" "${target_dir}/authorized_keys"
chmod 700 "${target_dir}" 2>/dev/null || true
chmod 600 "${target_dir}/authorized_keys" 2>/dev/null || true
ls -ld "${target_dir}" "${target_dir}/authorized_keys" 2>/dev/null || true
done
killall -HUP sshd 2>/dev/null || true
echo
echo "=== DONE ==="
echo "${OUT_DIR}"

View File

@@ -0,0 +1,44 @@
#!/bin/sh
set -eu
# 强制清理残留 SSH 进程,然后在 22 端口拉起一份 usbnet 自带的 DropBear。
# 这里使用 Kindle hack 里的 -n让其不走密码检查方便恢复公钥访问。
TS="$(date +%Y%m%d-%H%M%S 2>/dev/null || echo now)"
OUT_DIR="/mnt/us/ssh-debug/${TS}"
LOG_FILE="${OUT_DIR}/force-dropbear-22.log"
PID_FILE="/mnt/us/usbnet/run/dropbear-force-22.pid"
mkdir -p "${OUT_DIR}" /mnt/us/usbnet/run
exec >"${LOG_FILE}" 2>&1
echo "=== FORCE DROPBEAR 22 ==="
date 2>/dev/null || true
id 2>/dev/null || true
killall sshd 2>/dev/null || true
killall dropbear 2>/dev/null || true
killall dropbearmulti 2>/dev/null || true
sleep 1
rm -f "${PID_FILE}" 2>/dev/null || true
iptables -I INPUT 1 -p tcp --dport 22 -j ACCEPT 2>/dev/null || true
(
cd /mnt/us/usbnet
exec bin/dropbearmulti dropbear -F -E -p 22 -P "${PID_FILE}" -n
) &
LAUNCHER_PID="$!"
echo "${LAUNCHER_PID}" > "${OUT_DIR}/launcher.pid"
sleep 1
echo "launcher pid: ${LAUNCHER_PID}"
echo "pid file: ${PID_FILE}"
if [ -x /mnt/us/usbnet/bin/lsof ]; then
/mnt/us/usbnet/bin/lsof -n -P -iTCP:22 2>/dev/null || true
fi
echo "=== DONE ==="
echo "${OUT_DIR}"

View File

@@ -0,0 +1,63 @@
#!/bin/sh
set -eu
# 强制清理残留 SSH 进程,然后在 22 端口拉起一份 usbnet 自带的 OpenSSH。
# 这份 sshd 会优先读取 /mnt/us/usbnet/etc/dot.ssh/authorized_keys。
TS="$(date +%Y%m%d-%H%M%S 2>/dev/null || echo now)"
OUT_DIR="/mnt/us/ssh-debug/${TS}"
LOG_FILE="${OUT_DIR}/force-openssh-22.log"
PID_FILE="/mnt/us/usbnet/run/sshd-force-22.pid"
SOURCE_KEYS="/mnt/us/usbnet/etc/authorized_keys"
TARGET_KEYS="/mnt/us/usbnet/etc/dot.ssh/authorized_keys"
mkdir -p "${OUT_DIR}" /mnt/us/usbnet/run /mnt/us/usbnet/etc/dot.ssh
exec >"${LOG_FILE}" 2>&1
echo "=== FORCE OPENSSH 22 ==="
date 2>/dev/null || true
id 2>/dev/null || true
if [ -f "${SOURCE_KEYS}" ]; then
cp "${SOURCE_KEYS}" "${TARGET_KEYS}"
chmod 600 "${TARGET_KEYS}" 2>/dev/null || true
fi
chmod 755 /mnt/us/usbnet/etc/dot.ssh 2>/dev/null || true
killall sshd 2>/dev/null || true
killall dropbear 2>/dev/null || true
killall dropbearmulti 2>/dev/null || true
sleep 1
rm -f "${PID_FILE}" 2>/dev/null || true
iptables -I INPUT 1 -p tcp --dport 22 -j ACCEPT 2>/dev/null || true
(
exec /mnt/us/usbnet/sbin/sshd -D -e \
-f /mnt/us/usbnet/etc/sshd_config \
-o ListenAddress=0.0.0.0 \
-o Port=22 \
-o PidFile="${PID_FILE}" \
-o AuthorizedKeysFile="${TARGET_KEYS}" \
-o PasswordAuthentication=no \
-o KbdInteractiveAuthentication=no \
-o PubkeyAuthentication=yes \
-o PermitRootLogin=yes \
-o HostKey=/mnt/us/usbnet/etc/ssh_host_rsa_key \
-o HostKey=/mnt/us/usbnet/etc/ssh_host_ecdsa_key \
-o HostKey=/mnt/us/usbnet/etc/ssh_host_ed25519_key
) &
LAUNCHER_PID="$!"
echo "${LAUNCHER_PID}" > "${OUT_DIR}/launcher.pid"
sleep 1
echo "launcher pid: ${LAUNCHER_PID}"
echo "pid file: ${PID_FILE}"
if [ -x /mnt/us/usbnet/bin/lsof ]; then
/mnt/us/usbnet/bin/lsof -n -P -iTCP:22 2>/dev/null || true
fi
echo "=== DONE ==="
echo "${OUT_DIR}"

View File

@@ -0,0 +1,28 @@
#!/bin/sh
set -eu
# 停掉常见 SSH 进程,并清理掉常见 pid 文件。
TS="$(date +%Y%m%d-%H%M%S 2>/dev/null || echo now)"
OUT_DIR="/mnt/us/ssh-debug/${TS}"
LOG_FILE="${OUT_DIR}/stop-all.log"
mkdir -p "${OUT_DIR}"
exec >"${LOG_FILE}" 2>&1
echo "=== STOP ALL SSH DAEMONS ==="
date 2>/dev/null || true
id 2>/dev/null || true
killall sshd 2>/dev/null || true
killall dropbear 2>/dev/null || true
killall dropbearmulti 2>/dev/null || true
rm -f /mnt/us/usbnet/run/sshd.pid 2>/dev/null || true
rm -f /mnt/us/usbnet/run/sshd-force-22.pid 2>/dev/null || true
rm -f /mnt/us/usbnet/run/dropbear-2222.pid 2>/dev/null || true
rm -f /mnt/us/usbnet/run/dropbear-force-22.pid 2>/dev/null || true
echo "=== DONE ==="
echo "${OUT_DIR}"