// MsgSyncReq: run commands on the remote host // Copyright (C) 2021 Simon Ruderich // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . package sync import ( "fmt" "os" "os/exec" "strings" "ruderich.org/simon/safcm" "ruderich.org/simon/safcm/cmd/safcm-remote/run" ) func (s *Sync) syncCommands() error { // Run triggered commands first for _, path := range s.triggers { for _, x := range s.req.Files[path].TriggerCommands { err := s.syncCommand(x, "", path) if err != nil { return err } } } // Regular commands afterwards so they can react on triggers if // necessary for _, x := range s.req.Commands { err := s.syncCommand(x.Cmd, x.OrigGroup, "") if err != nil { return err } } return nil } func (s *Sync) syncCommand(command, group, trigger string) error { s.resp.CommandChanges = append(s.resp.CommandChanges, safcm.CommandChange{ Command: command, Trigger: trigger, }) if s.req.DryRun { return nil } change := &s.resp.CommandChanges[len(s.resp.CommandChanges)-1] var info string if trigger != "" { info = fmt.Sprintf("%q", trigger) } else if group != "" { info = group } cmd := exec.Command("/bin/sh", "-c", command) cmd.Env = safcmEnviroment(s.req.Groups) // Cannot use cmd.CombinedOutputCmd() because we need another log // level (here the command is the actual change and not a side effect) // and different error handling. s.log.Verbosef("commands: running %s (%s)", run.QuoteForDebug(cmd), info) out, err := s.cmd.Runner.CombinedOutput(cmd) if len(out) > 0 { s.log.Debug2f("commands: command output:\n%s", out) } change.Output = string(out) if err != nil { change.Error = err.Error() return fmt.Errorf("%q failed: %v", command, err) } return nil } func safcmEnviroment(groups []string) []string { exe, err := os.Executable() if err != nil { panic(err) // should not happen on supported systems } env := os.Environ() // Provide additional environment variables env = append(env, fmt.Sprintf("SAFCM_HELPER=%s", exe), fmt.Sprintf("SAFCM_GROUPS=%s", strings.Join(groups, " "))) for _, x := range groups { env = append(env, fmt.Sprintf("SAFCM_GROUP_%s=%s", x, x)) } return env }