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,
|
|
|
|
},
|
2022-01-11 16:05:08 +01:00
|
|
|
linuxSystemService{
|
|
|
|
name: "linux-openrc",
|
|
|
|
detect: isOpenRC,
|
|
|
|
interactive: func() bool {
|
|
|
|
is, _ := isInteractive()
|
|
|
|
return is
|
|
|
|
},
|
|
|
|
new: newOpenRCService,
|
|
|
|
},
|
2018-01-17 11:28:43 +01:00
|
|
|
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)
|
|
|
|
},
|
|
|
|
}
|