1 Commits

2 changed files with 51 additions and 27 deletions

View File

@@ -112,30 +112,39 @@ func main() {
Short: "废除并移除在册的后台服务、扫除环境关联残留", Short: "废除并移除在册的后台服务、扫除环境关联残留",
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
service.Control(svc, "stop") service.Control(svc, "stop")
handleServiceControl(svc, "uninstall") if !handleServiceControl(svc, "uninstall") {
return
}
targetDir, targetExe := getTargetSystemPath() targetDir, targetExe := getTargetSystemPath()
currentExe, _ := os.Executable() currentExe, _ := os.Executable()
isSelfExe := strings.EqualFold(filepath.Clean(currentExe), filepath.Clean(targetExe))
if !strings.EqualFold(filepath.Clean(currentExe), filepath.Clean(targetExe)) { // Clean up PATH (Windows)
if _, err := os.Stat(targetExe); err == nil {
logger.Debug("查明环境曾记录过全局部署逻辑,现已启动强力移除可执行源地址流: %s", targetExe)
os.Remove(targetExe)
if runtime.GOOS == "windows" { if runtime.GOOS == "windows" {
os.Remove(targetDir)
envClearCmd := fmt.Sprintf(`$p=[Environment]::GetEnvironmentVariable("Path","Machine");$np=($p -split ';' | Where-Object {$_ -ne "%s" -and $_ -ne ""}) -join ';';[Environment]::SetEnvironmentVariable("Path",$np,"Machine")`, targetDir) envClearCmd := fmt.Sprintf(`$p=[Environment]::GetEnvironmentVariable("Path","Machine");$np=($p -split ';' | Where-Object {$_ -ne "%s" -and $_ -ne ""}) -join ';';[Environment]::SetEnvironmentVariable("Path",$np,"Machine")`, targetDir)
exec.Command("powershell", "-Command", envClearCmd).Run() exec.Command("powershell", "-Command", envClearCmd).Run()
logger.Debug("环境变量系统清理Windows Global Path 中的指向挂载项业已剥除卸载完成。") logger.Debug("环境变量系统清理Windows Global Path 中的指向挂载项业已剥除卸载完成。")
} }
// Delete executable
if _, err := os.Stat(targetExe); err == nil {
if isSelfExe && runtime.GOOS == "windows" {
// Windows: cannot delete a running exe, use delayed self-deletion
delCmd := fmt.Sprintf(`ping 127.0.0.1 -n 2 > nul & del "%s" & rmdir "%s"`, targetExe, targetDir)
exec.Command("cmd", "/C", "start", "/min", "cmd", "/C", delCmd).Start()
logger.Debug("已调度延迟自删除任务: %s", targetExe)
} else {
os.Remove(targetExe)
if runtime.GOOS == "windows" {
os.Remove(targetDir)
}
logger.Debug("已移除可执行文件: %s", targetExe)
} }
} }
if config.ConfirmConfigCleanup() { // Prompt for config and log cleanup
configDir := config.GetConfigDir() config.ConfirmAndCleanup()
os.RemoveAll(configDir)
fmt.Println("配置文件与日志已清除。")
}
}, },
}, },
{ {
@@ -287,18 +296,19 @@ func main() {
} }
} }
func handleServiceControl(s service.Service, action string) { func handleServiceControl(s service.Service, action string) bool {
err := service.Control(s, action) err := service.Control(s, action)
if err != nil { if err != nil {
errStr := err.Error() errStr := err.Error()
if strings.Contains(errStr, "Access is denied") || strings.Contains(errStr, "permission denied") || strings.Contains(errStr, "拒绝访问") { if strings.Contains(errStr, "Access is denied") || strings.Contains(errStr, "permission denied") || strings.Contains(errStr, "拒绝访问") {
logger.Fail("管控流程 [%s] 触发越级防卫!无核准身份特设记录。请开具含有全 Root 及高配权限窗格承接口径。", action) logger.Fail("管控流程 [%s] 触发越级防卫!无核准身份特设记录。请开具含有全 Root 及高配权限窗格承接口径。", action)
return return false
} }
logger.Crit("后台执行流程组块阻断报错 [%s] : %v", action, err) logger.Crit("后台执行流程组块阻断报错 [%s] : %v", action, err)
return return false
} }
logger.Succ("指令动作 [%s] 解析下发执行完毕,无阻断警告。", action) logger.Succ("指令动作 [%s] 解析下发执行完毕,无阻断警告。", action)
return true
} }
func printLastLogLines(n int) { func printLastLogLines(n int) {

View File

@@ -63,25 +63,39 @@ func InteractiveSetup() (*Config, error) {
return cfg, nil return cfg, nil
} }
// ConfirmConfigCleanup prompts the user to confirm deletion of config and log files. // ConfirmAndCleanup prompts the user to confirm deletion of config and log files separately.
// Returns true if the user confirms. Non-terminal stdin defaults to no. // Non-terminal stdin skips all prompts.
func ConfirmConfigCleanup() bool { func ConfirmAndCleanup() {
if !isTerminal() { if !isTerminal() {
return false return
} }
scanner := bufio.NewScanner(os.Stdin)
configDir := GetConfigDir() configDir := GetConfigDir()
configPath := filepath.Join(configDir, "config.json") configPath := filepath.Join(configDir, "config.json")
if _, err := os.Stat(configPath); err != nil { logDir := GetLogDir()
return false
if _, err := os.Stat(configPath); err == nil {
fmt.Printf("检测到配置文件: %s\n是否清除配置文件[y/N]: ", configPath)
if scanner.Scan() && strings.EqualFold(strings.TrimSpace(scanner.Text()), "y") {
os.Remove(configPath)
fmt.Println("配置文件已清除。")
}
} }
fmt.Printf("检测到配置文件: %s\n是否一并清除配置文件与日志[y/N]: ", configDir) if _, err := os.Stat(logDir); err == nil {
scanner := bufio.NewScanner(os.Stdin) fmt.Printf("检测到日志目录: %s\n是否清除日志文件[y/N]: ", logDir)
if scanner.Scan() { if scanner.Scan() && strings.EqualFold(strings.TrimSpace(scanner.Text()), "y") {
return strings.EqualFold(strings.TrimSpace(scanner.Text()), "y") os.RemoveAll(logDir)
fmt.Println("日志文件已清除。")
}
}
// If configDir is now empty, remove it too
entries, err := os.ReadDir(configDir)
if err == nil && len(entries) == 0 {
os.Remove(configDir)
} }
return false
} }
func promptString(scanner *bufio.Scanner, label, defaultVal string, validate func(string) error) string { func promptString(scanner *bufio.Scanner, label, defaultVal string, validate func(string) error) string {