dnscrypt-proxy/vendor/github.com/kardianos/service/service_linux.go

135 lines
2.7 KiB
Go
Raw Normal View History

2018-01-17 11:28:43 +01:00
// Copyright 2015 Daniel Theophanes.
// Use of this source code is governed by a zlib-style
// license that can be found in the LICENSE file.
package service
import (
2019-11-17 22:54:56 +01:00
"bufio"
2020-11-18 10:19:58 +01:00
"fmt"
"io/ioutil"
2018-01-17 11:28:43 +01:00
"os"
"strings"
)
2019-11-17 22:54:56 +01:00
var cgroupFile = "/proc/1/cgroup"
2018-01-17 11:28:43 +01:00
type linuxSystemService struct {
name string
detect func() bool
interactive func() bool
2018-10-02 18:06:43 +02:00
new func(i Interface, platform string, c *Config) (Service, error)
2018-01-17 11:28:43 +01:00
}
func (sc linuxSystemService) String() string {
return sc.name
}
func (sc linuxSystemService) Detect() bool {
return sc.detect()
}
func (sc linuxSystemService) Interactive() bool {
return sc.interactive()
}
func (sc linuxSystemService) New(i Interface, c *Config) (Service, error) {
2018-10-02 18:06:43 +02:00
return sc.new(i, sc.String(), c)
2018-01-17 11:28:43 +01:00
}
func init() {
ChooseSystem(linuxSystemService{
name: "linux-systemd",
detect: isSystemd,
interactive: func() bool {
is, _ := isInteractive()
return is
},
new: newSystemdService,
},
linuxSystemService{
name: "linux-upstart",
detect: isUpstart,
interactive: func() bool {
is, _ := isInteractive()
return is
},
new: newUpstartService,
},
linuxSystemService{
name: "unix-systemv",
detect: func() bool { return true },
interactive: func() bool {
is, _ := isInteractive()
return is
},
new: newSystemVService,
},
)
}
2020-11-18 10:19:58 +01:00
func binaryName(pid int) (string, error) {
statPath := fmt.Sprintf("/proc/%d/stat", pid)
dataBytes, err := ioutil.ReadFile(statPath)
if err != nil {
return "", err
}
// First, parse out the image name
data := string(dataBytes)
binStart := strings.IndexRune(data, '(') + 1
binEnd := strings.IndexRune(data[binStart:], ')')
return data[binStart : binStart+binEnd], nil
}
2018-01-17 11:28:43 +01:00
func isInteractive() (bool, error) {
2019-11-17 22:54:56 +01:00
inContainer, err := isInContainer(cgroupFile)
if err != nil {
return false, err
}
2020-11-18 10:19:58 +01:00
if inContainer {
return true, nil
}
ppid := os.Getppid()
if ppid == 1 {
return false, nil
}
binary, _ := binaryName(ppid)
return binary != "systemd", nil
2019-11-17 22:54:56 +01:00
}
// isInContainer checks if the service is being executed in docker or lxc
// container.
func isInContainer(cgroupPath string) (bool, error) {
const maxlines = 5 // maximum lines to scan
f, err := os.Open(cgroupPath)
if err != nil {
return false, err
}
defer f.Close()
scan := bufio.NewScanner(f)
lines := 0
for scan.Scan() && !(lines > maxlines) {
if strings.Contains(scan.Text(), "docker") || strings.Contains(scan.Text(), "lxc") {
return true, nil
}
lines++
}
if err := scan.Err(); err != nil {
return false, err
}
return false, nil
2018-01-17 11:28:43 +01:00
}
var tf = map[string]interface{}{
"cmd": func(s string) string {
return `"` + strings.Replace(s, `"`, `\"`, -1) + `"`
},
"cmdEscape": func(s string) string {
return strings.Replace(s, " ", `\x20`, -1)
},
}