mirror of
https://github.com/hotwa/luci-app-openclaw.git
synced 2026-03-30 12:15:44 +00:00
release: v1.0.6 — Docker OverlayFS 兼容性修复
This commit is contained in:
12
CHANGELOG.md
12
CHANGELOG.md
@@ -4,6 +4,18 @@
|
||||
|
||||
格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.0.0/)。
|
||||
|
||||
## [1.0.6] - 2026-03-06
|
||||
|
||||
### 修复 Docker 环境下安装失败 "mkdir: can't create directory: Directory not empty"
|
||||
|
||||
#### 修复
|
||||
- **OverlayFS 兼容性**: iStoreOS/OpenWrt 安装 Docker 后,Docker 的 bind mount (`/overlay/upper/opt/docker`) 导致 OverlayFS 合并视图中 `/opt` 目录完全不可写,所有 `mkdir`/`touch`/`ln` 操作均报 "Directory not empty"
|
||||
- 新增 `_oc_fix_opt()` 检测函数,自动检测 `/opt` 是否可写
|
||||
- 不可写时自动执行 `mount --bind /overlay/upper/opt /opt` 绕过 OverlayFS 冲突
|
||||
- 三重保障: `uci-defaults` (首次安装)、`init.d` (每次开机)、`openclaw-env` (手动操作) 均包含修复逻辑
|
||||
- 正常系统 (无 Docker) 不受影响,检测到可写后直接跳过
|
||||
- **openclaw-env**: 新增 `ensure_mkdir()` 安全目录创建函数,替代所有裸 `mkdir -p` 调用
|
||||
|
||||
## [1.0.5] - 2026-03-05
|
||||
|
||||
### 修复配置管理页面 "spawn script ENOENT" 启动失败 (#3, #4)
|
||||
|
||||
@@ -13,6 +13,20 @@ EXTRA_HELP=" setup 下载 Node.js 并安装 OpenClaw
|
||||
NODE_BASE="/opt/openclaw/node"
|
||||
OC_GLOBAL="/opt/openclaw/global"
|
||||
OC_DATA="/opt/openclaw/data"
|
||||
|
||||
# ── OverlayFS 兼容性修复 ──
|
||||
# Docker bind mount (/overlay/upper/opt/docker) 会导致 /opt 不可写
|
||||
# 解决: bind mount upper 层的 /opt 到合并视图的 /opt
|
||||
_oc_fix_opt() {
|
||||
mkdir -p /opt/openclaw/.probe 2>/dev/null && { rmdir /opt/openclaw/.probe 2>/dev/null; return 0; }
|
||||
if [ -d /overlay/upper/opt ]; then
|
||||
mkdir -p /overlay/upper/opt/openclaw 2>/dev/null
|
||||
mount --bind /overlay/upper/opt /opt 2>/dev/null && return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
_oc_fix_opt
|
||||
|
||||
NODE_BIN="${NODE_BASE}/bin/node"
|
||||
CONFIG_FILE="${OC_DATA}/.openclaw/openclaw.json"
|
||||
|
||||
@@ -64,8 +78,8 @@ port=$(uci -q get openclaw.main.port || echo "18789")
|
||||
bind=$(uci -q get openclaw.main.bind || echo "lan")
|
||||
token=$(uci -q get openclaw.main.token || echo "")
|
||||
|
||||
# 确保配置目录和文件存在
|
||||
mkdir -p "$(dirname "$CONFIG_FILE")"
|
||||
# 确保配置目录和文件存在 (路径已在脚本开头做 OverlayFS 重映射)
|
||||
mkdir -p "$(dirname "$CONFIG_FILE")" 2>/dev/null
|
||||
if [ ! -f "$CONFIG_FILE" ]; then
|
||||
echo '{}' > "$CONFIG_FILE"
|
||||
fi
|
||||
|
||||
@@ -25,6 +25,16 @@ if ! id openclaw >/dev/null 2>&1; then
|
||||
fi
|
||||
|
||||
# 创建数据目录
|
||||
# ── OverlayFS 兼容: Docker bind mount 可能导致 /opt 不可写 ──
|
||||
if ! mkdir -p /opt/openclaw/.probe 2>/dev/null; then
|
||||
if [ -d /overlay/upper/opt ]; then
|
||||
mkdir -p /overlay/upper/opt/openclaw 2>/dev/null
|
||||
mount --bind /overlay/upper/opt /opt 2>/dev/null
|
||||
fi
|
||||
rmdir /opt/openclaw/.probe 2>/dev/null
|
||||
else
|
||||
rmdir /opt/openclaw/.probe 2>/dev/null
|
||||
fi
|
||||
mkdir -p /opt/openclaw/data/.openclaw
|
||||
mkdir -p /opt/openclaw/node
|
||||
mkdir -p /opt/openclaw/global
|
||||
|
||||
@@ -19,6 +19,28 @@ OC_VERSION="${OC_VERSION:-}"
|
||||
NODE_BASE="/opt/openclaw/node"
|
||||
OC_GLOBAL="/opt/openclaw/global"
|
||||
OC_DATA="/opt/openclaw/data"
|
||||
|
||||
# ── OverlayFS 兼容性修复 ──
|
||||
# iStoreOS/OpenWrt 上 Docker 的 bind mount (/overlay/upper/opt/docker)
|
||||
# 会导致 OverlayFS 合并视图中 /opt 完全不可写 (mkdir 报 "Directory not empty")。
|
||||
# 解决方案: 将 /overlay/upper/opt bind mount 到 /opt,绕过 OverlayFS 冲突。
|
||||
_oc_fix_opt() {
|
||||
# 如果 /opt 可正常写入,无需修复
|
||||
if mkdir -p /opt/openclaw/.probe 2>/dev/null; then
|
||||
rmdir /opt/openclaw/.probe 2>/dev/null
|
||||
return 0
|
||||
fi
|
||||
# /opt 不可写且 overlay upper 层存在 — 执行 bind mount 修复
|
||||
if [ -d /overlay/upper/opt ]; then
|
||||
# 确保 upper 层有 openclaw 目录
|
||||
mkdir -p /overlay/upper/opt/openclaw 2>/dev/null
|
||||
# 绑定挂载 upper 层的 /opt 到合并视图的 /opt
|
||||
mount --bind /overlay/upper/opt /opt 2>/dev/null && return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
_oc_fix_opt
|
||||
|
||||
NODE_BIN="${NODE_BASE}/bin/node"
|
||||
NPM_BIN="${NODE_BASE}/bin/npm"
|
||||
PNPM_BIN="${OC_GLOBAL}/bin/pnpm"
|
||||
@@ -38,6 +60,17 @@ log_info() { echo " [✓] $1"; }
|
||||
log_warn() { echo " [!] $1"; }
|
||||
log_error() { echo " [✗] $1"; }
|
||||
|
||||
# 安全创建目录 (会在 _oc_fix_opt 修复 /opt 后使用标准路径)
|
||||
ensure_mkdir() {
|
||||
local target="$1"
|
||||
[ -d "$target" ] && return 0
|
||||
if ! mkdir -p "$target" 2>/dev/null; then
|
||||
log_error "无法创建目录: $target"
|
||||
log_error "如果安装了 Docker,可能需要手动执行: mount --bind /overlay/upper/opt /opt"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 检测 C 运行时类型 (glibc vs musl)
|
||||
detect_libc() {
|
||||
if ldd --version 2>&1 | grep -qi musl; then
|
||||
@@ -184,8 +217,13 @@ download_node() {
|
||||
|
||||
# 解压
|
||||
echo " 正在解压到 ${NODE_BASE}..."
|
||||
rm -rf "$NODE_BASE"
|
||||
mkdir -p "$NODE_BASE"
|
||||
# OverlayFS 兼容: rm -rf 后可能因 whiteout 导致 mkdir 失败
|
||||
# 先尝试常规方式,失败则通过 overlay upper 层操作
|
||||
rm -rf "$NODE_BASE" 2>/dev/null
|
||||
if [ -d /overlay/upper ]; then
|
||||
rm -rf "/overlay/upper${NODE_BASE}" 2>/dev/null
|
||||
fi
|
||||
ensure_mkdir "$NODE_BASE"
|
||||
tar xf "$tmp_file" -C "$NODE_BASE" --strip-components=1
|
||||
rm -f "$tmp_file"
|
||||
|
||||
@@ -210,7 +248,7 @@ install_pnpm() {
|
||||
fi
|
||||
|
||||
# 使用 npm 安装 pnpm 到全局目录
|
||||
mkdir -p "$OC_GLOBAL"
|
||||
ensure_mkdir "$OC_GLOBAL"
|
||||
"$NPM_BIN" install -g pnpm --prefix="$OC_GLOBAL" 2>/dev/null
|
||||
|
||||
if [ -x "$OC_GLOBAL/bin/pnpm" ]; then
|
||||
@@ -264,7 +302,7 @@ install_openclaw() {
|
||||
# 优先用 npm 安装 (pnpm 在 musl 上全局安装可能有路径问题)
|
||||
local npm_ok=0
|
||||
if [ -x "$NPM_BIN" ]; then
|
||||
mkdir -p "$OC_GLOBAL"
|
||||
ensure_mkdir "$OC_GLOBAL"
|
||||
"$NPM_BIN" install -g "$oc_pkg" --prefix="$OC_GLOBAL" $install_flags 2>&1 | tail -10
|
||||
# 检查是否安装成功
|
||||
if [ -n "$(find_oc_entry)" ]; then
|
||||
@@ -275,7 +313,7 @@ install_openclaw() {
|
||||
[ -n "$(find_oc_entry)" ] && npm_ok=1
|
||||
fi
|
||||
elif [ -x "$PNPM_BIN" ]; then
|
||||
mkdir -p "$OC_GLOBAL"
|
||||
ensure_mkdir "$OC_GLOBAL"
|
||||
"$PNPM_BIN" install -g "$oc_pkg" --prefix="$OC_GLOBAL" 2>&1 | tail -5
|
||||
else
|
||||
log_error "npm 和 pnpm 均不可用"
|
||||
@@ -315,7 +353,7 @@ init_openclaw() {
|
||||
echo "=== 初始化 OpenClaw ==="
|
||||
|
||||
# 创建数据目录
|
||||
mkdir -p "$OC_DATA/.openclaw"
|
||||
ensure_mkdir "$OC_DATA/.openclaw"
|
||||
|
||||
# 运行 onboard
|
||||
local oc_entry=""
|
||||
@@ -516,7 +554,7 @@ do_factory_reset() {
|
||||
if [ -f "$config_file" ]; then
|
||||
local backup_dir="${config_dir}/backups"
|
||||
local backup_ts=$(date +%Y%m%d_%H%M%S)
|
||||
mkdir -p "$backup_dir"
|
||||
ensure_mkdir "$backup_dir"
|
||||
cp "$config_file" "${backup_dir}/openclaw_${backup_ts}.json"
|
||||
log_info "备份已保存: backups/openclaw_${backup_ts}.json"
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user