github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/supervisor/install/install_darwin.go (about) 1 /* 2 * Copyright (C) 2020 The "MysteriumNetwork/node" Authors. 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 3 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 package install 19 20 import ( 21 "errors" 22 "fmt" 23 "os" 24 "os/exec" 25 "strings" 26 "text/template" 27 28 "github.com/rs/zerolog/log" 29 ) 30 31 const daemonID = "network.mysterium.myst_supervisor" 32 const plistPath = "/Library/LaunchDaemons/" + daemonID + ".plist" 33 const plistTpl = ` 34 <?xml version="1.0" encoding="UTF-8"?> 35 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 36 <plist version="1.0"> 37 <dict> 38 <key>Label</key> 39 <string>{{.DaemonID}}</string> 40 <key>ProgramArguments</key> 41 <array> 42 <string>{{.SupervisorPath}}</string> 43 </array> 44 <key>KeepAlive</key> 45 <true/> 46 </dict> 47 </plist> 48 ` 49 50 // Install installs launchd supervisor daemon on Darwin OS. 51 func Install(options Options) error { 52 if !options.valid() { 53 return errInvalid 54 } 55 56 log.Info().Msg("Cleaning up previous installation") 57 clean() 58 59 log.Info().Msg("Installing launchd daemon") 60 tpl, err := template.New("plistTpl").Parse(plistTpl) 61 if err != nil { 62 return fmt.Errorf("could not create template for %s: %w", plistPath, err) 63 } 64 fd, err := os.Create(plistPath) 65 if err != nil { 66 return fmt.Errorf("could not create file %s: %w", plistPath, err) 67 } 68 err = tpl.Execute(fd, map[string]string{ 69 "DaemonID": daemonID, 70 "SupervisorPath": options.SupervisorPath, 71 }) 72 if err != nil { 73 return fmt.Errorf("could not generate %s: %w", plistPath, err) 74 } 75 out, err := runV("launchctl", "load", plistPath) 76 if err == nil && strings.Contains(out, "Invalid property") { 77 err = errors.New("invalid plist file") 78 } 79 if err != nil { 80 return fmt.Errorf("could not load launch daemon: %w", err) 81 } 82 return nil 83 } 84 85 // Uninstall launchd supervisor daemon on Darwin OS. 86 func Uninstall() error { 87 log.Info().Msg("Uninstalling launchd daemon") 88 return clean() 89 } 90 91 func clean() error { 92 if _, err := runV("launchctl", "unload", plistPath); err != nil { 93 return err 94 } 95 return os.RemoveAll(plistPath) 96 } 97 98 func runV(c ...string) (string, error) { 99 cmd := exec.Command(c[0], c[1:]...) 100 output, err := cmd.CombinedOutput() 101 log.Printf("[%v] out:\n%s", strings.Join(c, " "), output) 102 if err != nil { 103 return "", err 104 } 105 return string(output), nil 106 }