release: v1.0.6 — Docker OverlayFS 兼容性修复

This commit is contained in:
10000ge10000
2026-03-05 22:53:46 +08:00
parent ed583e38b2
commit 20a8c016a4
5 changed files with 84 additions and 10 deletions

View File

@@ -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)

View File

@@ -1 +1 @@
1.0.5
1.0.6

View File

@@ -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

View File

@@ -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

View File

@@ -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