github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/supervisor/install/install_windows.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 "time" 24 25 "github.com/rs/zerolog/log" 26 27 "golang.org/x/sys/windows" 28 "golang.org/x/sys/windows/svc" 29 "golang.org/x/sys/windows/svc/eventlog" 30 "golang.org/x/sys/windows/svc/mgr" 31 ) 32 33 const serviceName = "MysteriumVPNSupervisor" 34 35 // Install installs service for Windows. If there is previous service instance 36 // running it will be first uninstalled before installing new version. 37 func Install(options Options) error { 38 if !options.valid() { 39 return errInvalid 40 } 41 m, err := mgr.Connect() 42 if err != nil { 43 return fmt.Errorf("could not connect to service manager: %w", err) 44 } 45 defer m.Disconnect() 46 47 log.Info().Msg("Checking previous installation") 48 if err := uninstallService(m, serviceName); err != nil { 49 log.Info().Err(err).Msg("Previous service was not uninstalled") 50 } else { 51 if err := waitServiceDeleted(m, serviceName); err != nil { 52 return fmt.Errorf("could not wait for service to deletion: %w", err) 53 } 54 log.Info().Msg("Uninstalled previous service") 55 } 56 57 config := mgr.Config{ 58 ServiceType: windows.SERVICE_WIN32_OWN_PROCESS, 59 StartType: mgr.StartAutomatic, 60 ErrorControl: mgr.ErrorNormal, 61 DisplayName: "MysteriumVPN Supervisor", 62 Description: "Handles network configuration for MysteriumVPN application.", 63 Dependencies: []string{"Nsi"}, 64 } 65 if err := installAndStartService(m, serviceName, options, config); err != nil { 66 return fmt.Errorf("could not install and run service: %w", err) 67 } 68 return nil 69 } 70 71 // Uninstall uninstalls service for Windows. 72 func Uninstall() error { 73 m, err := mgr.Connect() 74 if err != nil { 75 return fmt.Errorf("could not connect to service manager: %w", err) 76 } 77 defer m.Disconnect() 78 79 return uninstallService(m, serviceName) 80 } 81 82 func installAndStartService(m *mgr.Mgr, name string, options Options, config mgr.Config) error { 83 s, err := m.CreateService(name, options.SupervisorPath, config, "-winservice") 84 if err != nil { 85 return fmt.Errorf("could not create service: %w", err) 86 } 87 defer s.Close() 88 89 err = eventlog.InstallAsEventCreate(name, eventlog.Error|eventlog.Warning|eventlog.Info) 90 if err != nil { 91 s.Delete() 92 return fmt.Errorf("could not configure event logging: %s", err) 93 } 94 95 if err := s.Start(); err != nil { 96 return fmt.Errorf("could not start service: %w", err) 97 } 98 return nil 99 } 100 101 func uninstallService(m *mgr.Mgr, name string) error { 102 s, err := m.OpenService(name) 103 if err != nil { 104 return fmt.Errorf("skipping uninstall, service %s is not installed", name) 105 } 106 defer s.Close() 107 108 // Send stop signal and ignore errors as if service is already stopped it will 109 // return error which we don't care about as we just want to delete service anyway. 110 s.Control(svc.Stop) 111 112 err = s.Delete() 113 if err != nil { 114 return fmt.Errorf("could not mark service for deletion: %w", err) 115 } 116 117 err = eventlog.Remove(name) 118 if err != nil { 119 return fmt.Errorf("cound not remove event logging: %s", err) 120 } 121 122 return nil 123 } 124 125 // waitServiceDeleted checks if service is deleted. 126 // It is considered as deleted if OpenService fails. 127 func waitServiceDeleted(m *mgr.Mgr, name string) error { 128 timeout := time.After(10 * time.Second) 129 for { 130 select { 131 case <-timeout: 132 return errors.New("timeout waiting for service deletion") 133 case <-time.After(100 * time.Millisecond): 134 s, err := m.OpenService(name) 135 if err != nil { 136 return nil 137 } 138 s.Close() 139 } 140 } 141 }