gitee.com/quant1x/gox@v1.21.2/daemon/daemon_linux_systemd.go (about) 1 // Copyright 2020 The Go Authors. All rights reserved. 2 // Use of this source code is governed by 3 // license that can be found in the LICENSE file. 4 5 package daemon 6 7 import ( 8 "os" 9 "os/exec" 10 "regexp" 11 "strings" 12 "text/template" 13 ) 14 15 // systemDRecord - standard record (struct) for linux systemD version of daemon package 16 type systemDRecord struct { 17 name string 18 description string 19 kind Kind 20 dependencies []string 21 } 22 23 // Standard service path for systemD daemons 24 func (linux *systemDRecord) servicePath() string { 25 return "/etc/systemd/system/" + linux.name + ".service" 26 } 27 28 // Is a service installed 29 func (linux *systemDRecord) isInstalled() bool { 30 31 if _, err := os.Stat(linux.servicePath()); err == nil { 32 return true 33 } 34 35 return false 36 } 37 38 // Check service is running 39 func (linux *systemDRecord) checkRunning() (string, bool) { 40 output, err := exec.Command("systemctl", "status", linux.name+".service").Output() 41 if err == nil { 42 if matched, err := regexp.MatchString("Active: active", string(output)); err == nil && matched { 43 reg := regexp.MustCompile("Main PID: ([0-9]+)") 44 data := reg.FindStringSubmatch(string(output)) 45 if len(data) > 1 { 46 return "Service (pid " + data[1] + ") is running...", true 47 } 48 return "Service is running...", true 49 } 50 } 51 52 return "Service is stopped", false 53 } 54 55 // Install the service 56 func (linux *systemDRecord) Install(args ...string) (string, error) { 57 installAction := "Install " + linux.description + ":" 58 59 if ok, err := checkPrivileges(); !ok { 60 return installAction + failed, err 61 } 62 63 srvPath := linux.servicePath() 64 65 if linux.isInstalled() { 66 return installAction + failed, ErrAlreadyInstalled 67 } 68 69 file, err := os.Create(srvPath) 70 if err != nil { 71 return installAction + failed, err 72 } 73 defer file.Close() 74 75 execPatch, err := executablePath(linux.name) 76 if err != nil { 77 return installAction + failed, err 78 } 79 80 templ, err := template.New("systemDConfig").Parse(systemDConfig) 81 if err != nil { 82 return installAction + failed, err 83 } 84 85 if err := templ.Execute( 86 file, 87 &struct { 88 Name, Description, Dependencies, Path, Args string 89 }{ 90 linux.name, 91 linux.description, 92 strings.Join(linux.dependencies, " "), 93 execPatch, 94 strings.Join(args, " "), 95 }, 96 ); err != nil { 97 return installAction + failed, err 98 } 99 100 if err := exec.Command("systemctl", "daemon-reload").Run(); err != nil { 101 return installAction + failed, err 102 } 103 104 if err := exec.Command("systemctl", "enable", linux.name+".service").Run(); err != nil { 105 return installAction + failed, err 106 } 107 108 return installAction + success, nil 109 } 110 111 // Remove the service 112 func (linux *systemDRecord) Remove() (string, error) { 113 removeAction := "Removing " + linux.description + ":" 114 115 if ok, err := checkPrivileges(); !ok { 116 return removeAction + failed, err 117 } 118 119 if !linux.isInstalled() { 120 return removeAction + failed, ErrNotInstalled 121 } 122 123 if err := exec.Command("systemctl", "disable", linux.name+".service").Run(); err != nil { 124 return removeAction + failed, err 125 } 126 127 if err := os.Remove(linux.servicePath()); err != nil { 128 return removeAction + failed, err 129 } 130 131 return removeAction + success, nil 132 } 133 134 // Start the service 135 func (linux *systemDRecord) Start() (string, error) { 136 startAction := "Starting " + linux.description + ":" 137 138 if ok, err := checkPrivileges(); !ok { 139 return startAction + failed, err 140 } 141 142 if !linux.isInstalled() { 143 return startAction + failed, ErrNotInstalled 144 } 145 146 if _, ok := linux.checkRunning(); ok { 147 return startAction + failed, ErrAlreadyRunning 148 } 149 150 if err := exec.Command("systemctl", "start", linux.name+".service").Run(); err != nil { 151 return startAction + failed, err 152 } 153 154 return startAction + success, nil 155 } 156 157 // Stop the service 158 func (linux *systemDRecord) Stop() (string, error) { 159 stopAction := "Stopping " + linux.description + ":" 160 161 if ok, err := checkPrivileges(); !ok { 162 return stopAction + failed, err 163 } 164 165 if !linux.isInstalled() { 166 return stopAction + failed, ErrNotInstalled 167 } 168 169 if _, ok := linux.checkRunning(); !ok { 170 return stopAction + failed, ErrAlreadyStopped 171 } 172 173 if err := exec.Command("systemctl", "stop", linux.name+".service").Run(); err != nil { 174 return stopAction + failed, err 175 } 176 177 return stopAction + success, nil 178 } 179 180 // Status - Get service status 181 func (linux *systemDRecord) Status() (string, error) { 182 183 if ok, err := checkPrivileges(); !ok { 184 return "", err 185 } 186 187 if !linux.isInstalled() { 188 return statNotInstalled, ErrNotInstalled 189 } 190 191 statusAction, _ := linux.checkRunning() 192 193 return statusAction, nil 194 } 195 196 // Run - Run service 197 func (linux *systemDRecord) Run(e Executable) (string, error) { 198 runAction := "Running " + linux.description + ":" 199 e.Run() 200 return runAction + " completed.", nil 201 } 202 203 // GetTemplate - gets service config template 204 func (linux *systemDRecord) GetTemplate() string { 205 return systemDConfig 206 } 207 208 // SetTemplate - sets service config template 209 func (linux *systemDRecord) SetTemplate(tplStr string) error { 210 systemDConfig = tplStr 211 return nil 212 } 213 214 var systemDConfig = `[Unit] 215 Description={{.Description}} 216 Requires={{.Dependencies}} 217 After={{.Dependencies}} 218 219 [Service] 220 PIDFile=/var/run/{{.Name}}.pid 221 ExecStartPre=/bin/rm -f /var/run/{{.Name}}.pid 222 ExecStart={{.Path}} {{.Args}} 223 Restart=on-failure 224 225 [Install] 226 WantedBy=multi-user.target 227 `