mirror of
https://github.com/tnb-labs/panel.git
synced 2026-10-13 16:58:05 +08:00
go vet 的 printf 分析器有两个硬条件:包装器签名必须是 (format string, args ...any),且函数体内不能给 format 形参赋值。pkg/shell 两条都不满足—— 老实现的 shell = fmt.Sprintf(shell, args...) 踩了后者,上一轮抽出的 buildShell(shell string, args []any) 踩了前者。结果是 330 多个调用点的格式 串从来没被检查过,在fe7cce62上用探针验证过确实如此。 改掉签名与写法后检查生效,扫出的 23 处都不是真错配,只是「非常量格式串」。 其中 7 处本就在做格式化(路径用 + 拼好再传进去),还原成真正的格式串;其余 命令串是上游拼好的整条,为它们恢复 shell.Exec / ExecWithOutput / ExecWithPipe。2fc68ed9删掉的那个 Exec 删的是第二份实现:它自带 exec.CommandContext 与 ApplyEnv,没有 newCmd 的 setpgid、cmd.Cancel 和 WaitDelay,正是孙子进程杀不掉 的来源,合并掉是对的。现在恢复的只是 newCmd + runBuffered 的一行入口,没有可 漂移的行为,包内 ExecWithLog / ExecWithLogAppend 早就是这个命名档位。继续用 "%s" 透传还有个副作用:preCheckArg 按整值精确匹配单个元字符设计,整条命令送 进去过检必然恒真。 停机时正在跑的任务被记成 Failed 并跳过清理命令。systemd 默认 KillMode= control-group,SIGTERM 发给整个 cgroup,任务的 bash 往往比运行器的 ctx 取消 先死,cmd.Wait() 返回时 taskCtx.Err() 还是 nil。根因是 runner 的 ctx 要经过 「信号 → quit 通道 → 主协程 select → runnerCancel」这条长链,改为直接挂在 signal.NotifyContext 上,取消与命令被杀几乎同时;定性前保留 200ms 宽限期兜住 剩余的调度差。关停顺序随之不再是决定性因素,上一轮为此做的调整可以撤掉。 CLI 此前用 context.TODO()。newCmd 统一 setpgid 之后 Ctrl+C 只打到前台进程组, 子进程照跑而 CLI 已经退出。改用 signal.NotifyContext,首次信号取消 ctx 整组 杀掉,再按一次恢复默认处理,可强退卡在不可取消段里的命令。 其余: - 关停三段各 30 秒最坏叠到 90 秒,正好撞上 systemd 默认的 TimeoutStopSec, 改为共用一个预算;runCancelShell 的清理超时同样从 60 秒收到 30 秒,否则 停机时清理必被 Wait 放弃后的进程退出砍断 - nginx -t 与 apachectl configtest 的输出在 stderr,上一轮改成 out, _ := 只 拿 stdout 永远是空串,补 2>&1 - apache 两处逐字相同的 reload 块抽成 reloadConfig;environment.go 的 typ → 可执行文件映射不再与 IsInstalled 各存一份 已知未改:pkg/webserver 的 Dialect 已有 ConfigTest 与 reload,nginx/apache 仍 在 app 层手拼命令(两者的 apachectl 路径已经漂移,一个裸命令一个全路径), caddy 与 openlitespeed 早已改用 d.Reload;收敛它会动到用户可见文案与 gotext msgid,另行处理。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>