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  }