diff --git a/dash/KUAL/kindle-dash/menu.json b/dash/KUAL/kindle-dash/menu.json index cb75b2d..abaf0bc 100644 --- a/dash/KUAL/kindle-dash/menu.json +++ b/dash/KUAL/kindle-dash/menu.json @@ -1,5 +1,7 @@ { "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"} ] -} \ No newline at end of file +} diff --git a/dash/README.md b/dash/README.md index bf9b99d..f4cb8fe 100644 --- a/dash/README.md +++ b/dash/README.md @@ -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`) +## 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 * 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). * 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 diff --git a/dash/docs/kindle-voyage-5.13.6-dual-ssh-playbook-zh.md b/dash/docs/kindle-voyage-5.13.6-dual-ssh-playbook-zh.md new file mode 100644 index 0000000..bfb9880 --- /dev/null +++ b/dash/docs/kindle-voyage-5.13.6-dual-ssh-playbook-zh.md @@ -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 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 22 +ssh +``` + +### 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,排障效率会比外部盲试高一个数量级。 diff --git a/dash/docs/layered-clock-plan.zh.md b/dash/docs/layered-clock-plan.zh.md index 00968d9..c886882 100644 --- a/dash/docs/layered-clock-plan.zh.md +++ b/dash/docs/layered-clock-plan.zh.md @@ -13,6 +13,11 @@ - 节点:`6:2` - 链接:`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 已明确: - `阳历当天` @@ -123,9 +128,64 @@ - 分针每分钟一个角度,共 `60` 张 - 时针如果要做到真正随分钟连续移动,需要 `12 * 60 = 720` 张 - 这些都是小尺寸 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 端存在稳定的本地绘线工具,再考虑把指针改成算法绘制;当前版本不依赖这个前提。 +### 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. 为什么不能只把表盘放进整页背景 这个问题必须单独说明。 @@ -275,14 +335,28 @@ kindle local: "height": 220 }, "clockFace": { - "path": "clock-face.png", - "managedOnKindle": true + "path": "assets/clock-face.png", + "managedOnKindle": true, + "designWidth": 220, + "designHeight": 220 }, "clockHands": { "hourPattern": "assets/hour-hand/%03d.png", "minutePattern": "assets/minute-hand/%02d.png", "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` 先按设计稿记录 - 真正接入 Kindle 时,要换算成最终截图分辨率下的实际像素值 +- `pivotSource` 表示指针锚点来自 Figma 素材内部圆点中心,而不是素材端点 +- `scaleWithClockFace=true` 表示运行时必须按表盘尺寸同步缩放指针长度与 `pivot` ## 8. Kindle 侧刷新策略 @@ -332,12 +408,13 @@ MobileRead Wiki 明确写了: - `hour_index = ((hour % 12) * 60 + minute) = 000..719` 3. 在固定坐标先画: - `clock-face.png` -4. 再画: +4. 根据当前 `clockRegion` 与素材基准尺寸计算统一缩放比例 +5. 以素材内部 `pivot` 对齐表盘中心,先画: - `hour-hand/.png` -5. 再画: +6. 再以素材内部 `pivot` 对齐表盘中心,画: - `minute-hand/.png` -6. 默认做局部/普通刷新 -7. 每 `10` 到 `15` 分钟对时钟区域补一次全刷,清理残影 +7. 默认做局部/普通刷新 +8. 每 `10` 到 `15` 分钟对时钟区域补一次全刷,清理残影 ### 8.3 功耗模型 @@ -412,6 +489,8 @@ export CLOCK_FULL_REFRESH_INTERVAL_MINUTES=15 - 产出 `clock-face.png` - 产出 `hour-hand` 与 `minute-hand` 素材库 +- 明确每类指针素材的 `pivot` 与基准表盘尺寸 +- 确保时针、分针长度能随表盘尺寸同比例缩放适配 输出: @@ -443,7 +522,7 @@ export CLOCK_FULL_REFRESH_INTERVAL_MINUTES=15 - 本地 `minute-hand/*.png` 4. 分钟刷新时: - 先重画表盘 - - 再重画时针 - - 再重画分针 + - 再按 `pivot + scale` 规则重画时针 + - 再按 `pivot + scale` 规则重画分针 也就是说,**背景是远端低频资源,时钟是本地高频资源,二者不要混在同一个刷新链路里**。 diff --git a/dash/src/dash.sh b/dash/src/dash.sh index a1eaa09..cc30680 100755 --- a/dash/src/dash.sh +++ b/dash/src/dash.sh @@ -10,6 +10,7 @@ LOW_BATTERY_CMD="$DIR/local/low-battery.sh" REFRESH_SCHEDULE=${REFRESH_SCHEDULE:-"2,32 8-17 * * MON-FRI"} FULL_DISPLAY_REFRESH_RATE=${FULL_DISPLAY_REFRESH_RATE:-0} SLEEP_SCREEN_INTERVAL=${SLEEP_SCREEN_INTERVAL:-3600} +DISABLE_SYSTEM_SUSPEND=${DISABLE_SYSTEM_SUSPEND:-false} RTC=/sys/devices/platform/mxc_rtc.0/wakeup_enable LOW_BATTERY_REPORTING=${LOW_BATTERY_REPORTING:-false} @@ -27,6 +28,10 @@ init() { 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 initctl stop webreader >/dev/null 2>&1 echo powersave >/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor @@ -88,6 +93,9 @@ rtc_sleep() { if [ "$DEBUG" = true ]; then sleep "$duration" + elif [ "$DISABLE_SYSTEM_SUSPEND" = true ]; then + echo "Skipping system suspend, sleeping for ${duration}s instead" + sleep "$duration" else # shellcheck disable=SC2039 [ "$(cat "$RTC")" -eq 0 ] && echo -n "$duration" >"$RTC" diff --git a/dash/src/debug-off.sh b/dash/src/debug-off.sh new file mode 100755 index 0000000..382e41c --- /dev/null +++ b/dash/src/debug-off.sh @@ -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。" diff --git a/dash/src/debug-on.sh b/dash/src/debug-on.sh new file mode 100755 index 0000000..9b6b26b --- /dev/null +++ b/dash/src/debug-on.sh @@ -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。" diff --git a/dash/src/local/env.sh b/dash/src/local/env.sh index 2e74d96..2d5cc7f 100644 --- a/dash/src/local/env.sh +++ b/dash/src/local/env.sh @@ -13,6 +13,11 @@ export TIMEZONE=${TIMEZONE:-"Asia/Shanghai"} # 等图片尺寸与刷新逻辑确认无误后,再改回 4 之类的值以节省功耗。 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, # the dashboard will not be refreshed anymore, but instead show a # 'kindle is sleeping' screen. This can be useful if your schedule only runs diff --git a/dash/src/start-debug.sh b/dash/src/start-debug.sh new file mode 100755 index 0000000..e2bd070 --- /dev/null +++ b/dash/src/start-debug.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env sh + +# 调试启动脚本:强制关闭系统挂起,便于在 Kindle 上持续观察刷新效果。 +DIR="$(dirname "$0")" + +export DISABLE_SYSTEM_SUSPEND=true + +exec "$DIR/start.sh" diff --git a/dash/staging/device/dashboard/debug-off.sh b/dash/staging/device/dashboard/debug-off.sh new file mode 100755 index 0000000..382e41c --- /dev/null +++ b/dash/staging/device/dashboard/debug-off.sh @@ -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。" diff --git a/dash/staging/device/dashboard/debug-on.sh b/dash/staging/device/dashboard/debug-on.sh new file mode 100755 index 0000000..9b6b26b --- /dev/null +++ b/dash/staging/device/dashboard/debug-on.sh @@ -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。" diff --git a/dash/staging/device/dashboard/start-debug.sh b/dash/staging/device/dashboard/start-debug.sh new file mode 100755 index 0000000..e2bd070 --- /dev/null +++ b/dash/staging/device/dashboard/start-debug.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env sh + +# 调试启动脚本:强制关闭系统挂起,便于在 Kindle 上持续观察刷新效果。 +DIR="$(dirname "$0")" + +export DISABLE_SYSTEM_SUSPEND=true + +exec "$DIR/start.sh" diff --git a/dash/staging/device/extensions/kindle-dash/menu.json b/dash/staging/device/extensions/kindle-dash/menu.json index cb75b2d..abaf0bc 100644 --- a/dash/staging/device/extensions/kindle-dash/menu.json +++ b/dash/staging/device/extensions/kindle-dash/menu.json @@ -1,5 +1,7 @@ { "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"} ] -} \ No newline at end of file +} diff --git a/dash/staging/kindle-dash-release/debug-off.sh b/dash/staging/kindle-dash-release/debug-off.sh new file mode 100755 index 0000000..382e41c --- /dev/null +++ b/dash/staging/kindle-dash-release/debug-off.sh @@ -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。" diff --git a/dash/staging/kindle-dash-release/debug-on.sh b/dash/staging/kindle-dash-release/debug-on.sh new file mode 100755 index 0000000..9b6b26b --- /dev/null +++ b/dash/staging/kindle-dash-release/debug-on.sh @@ -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。" diff --git a/dash/staging/kindle-dash-release/start-debug.sh b/dash/staging/kindle-dash-release/start-debug.sh new file mode 100755 index 0000000..e2bd070 --- /dev/null +++ b/dash/staging/kindle-dash-release/start-debug.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env sh + +# 调试启动脚本:强制关闭系统挂起,便于在 Kindle 上持续观察刷新效果。 +DIR="$(dirname "$0")" + +export DISABLE_SYSTEM_SUSPEND=true + +exec "$DIR/start.sh" diff --git a/dash/staging/post-jailbreak-root/dashboard/debug-off.sh b/dash/staging/post-jailbreak-root/dashboard/debug-off.sh new file mode 100755 index 0000000..382e41c --- /dev/null +++ b/dash/staging/post-jailbreak-root/dashboard/debug-off.sh @@ -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。" diff --git a/dash/staging/post-jailbreak-root/dashboard/debug-on.sh b/dash/staging/post-jailbreak-root/dashboard/debug-on.sh new file mode 100755 index 0000000..9b6b26b --- /dev/null +++ b/dash/staging/post-jailbreak-root/dashboard/debug-on.sh @@ -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。" diff --git a/dash/staging/post-jailbreak-root/dashboard/start-debug.sh b/dash/staging/post-jailbreak-root/dashboard/start-debug.sh new file mode 100755 index 0000000..e2bd070 --- /dev/null +++ b/dash/staging/post-jailbreak-root/dashboard/start-debug.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env sh + +# 调试启动脚本:强制关闭系统挂起,便于在 Kindle 上持续观察刷新效果。 +DIR="$(dirname "$0")" + +export DISABLE_SYSTEM_SUSPEND=true + +exec "$DIR/start.sh" diff --git a/dash/staging/post-jailbreak-root/extensions/kindle-dash/menu.json b/dash/staging/post-jailbreak-root/extensions/kindle-dash/menu.json index cb75b2d..abaf0bc 100644 --- a/dash/staging/post-jailbreak-root/extensions/kindle-dash/menu.json +++ b/dash/staging/post-jailbreak-root/extensions/kindle-dash/menu.json @@ -1,5 +1,7 @@ { "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"} ] -} \ No newline at end of file +} diff --git a/scripts/connect-kindle-usbnet-mac.sh b/scripts/connect-kindle-usbnet-mac.sh new file mode 100755 index 0000000..cd17b23 --- /dev/null +++ b/scripts/connect-kindle-usbnet-mac.sh @@ -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 diff --git a/scripts/kindle/ssh-collect.sh b/scripts/kindle/ssh-collect.sh new file mode 100644 index 0000000..2ef1b85 --- /dev/null +++ b/scripts/kindle/ssh-collect.sh @@ -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}" diff --git a/scripts/kindle/ssh-fix-all-keys.sh b/scripts/kindle/ssh-fix-all-keys.sh new file mode 100644 index 0000000..63c62d3 --- /dev/null +++ b/scripts/kindle/ssh-fix-all-keys.sh @@ -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}" diff --git a/scripts/kindle/ssh-force-dropbear-22.sh b/scripts/kindle/ssh-force-dropbear-22.sh new file mode 100644 index 0000000..7acd62e --- /dev/null +++ b/scripts/kindle/ssh-force-dropbear-22.sh @@ -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}" diff --git a/scripts/kindle/ssh-force-openssh-22.sh b/scripts/kindle/ssh-force-openssh-22.sh new file mode 100644 index 0000000..869c925 --- /dev/null +++ b/scripts/kindle/ssh-force-openssh-22.sh @@ -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}" diff --git a/scripts/kindle/ssh-stop-all.sh b/scripts/kindle/ssh-stop-all.sh new file mode 100644 index 0000000..802b751 --- /dev/null +++ b/scripts/kindle/ssh-stop-all.sh @@ -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}"