-
-
Notifications
You must be signed in to change notification settings - Fork 5
/
helpers.go
134 lines (123 loc) · 3.48 KB
/
helpers.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package systemctl
import (
"context"
"errors"
"strconv"
"strings"
"time"
"github.com/taigrr/systemctl/properties"
)
const dateFormat = "Mon 2006-01-02 15:04:05 MST"
// Get start time of a service (`systemctl show [unit] --property ExecMainStartTimestamp`) as a `Time` type
func GetStartTime(ctx context.Context, unit string, opts Options) (time.Time, error) {
value, err := Show(ctx, unit, properties.ExecMainStartTimestamp, opts)
if err != nil {
return time.Time{}, err
}
// ExecMainStartTimestamp returns an empty string if the unit is not running
if value == "" {
return time.Time{}, ErrUnitNotActive
}
return time.Parse(dateFormat, value)
}
// Get the number of times a process restarted (`systemctl show [unit] --property NRestarts`) as an int
func GetNumRestarts(ctx context.Context, unit string, opts Options) (int, error) {
value, err := Show(ctx, unit, properties.NRestarts, opts)
if err != nil {
return -1, err
}
return strconv.Atoi(value)
}
// Get current memory in bytes (`systemctl show [unit] --property MemoryCurrent`) an an int
func GetMemoryUsage(ctx context.Context, unit string, opts Options) (int, error) {
value, err := Show(ctx, unit, properties.MemoryCurrent, opts)
if err != nil {
return -1, err
}
if value == "[not set]" {
return -1, ErrValueNotSet
}
return strconv.Atoi(value)
}
// Get the PID of the main process (`systemctl show [unit] --property MainPID`) as an int
func GetPID(ctx context.Context, unit string, opts Options) (int, error) {
value, err := Show(ctx, unit, properties.MainPID, opts)
if err != nil {
return -1, err
}
return strconv.Atoi(value)
}
func GetUnits(ctx context.Context, opts Options) ([]Unit, error) {
args := []string{"list-units", "--all", "--no-legend", "--full", "--no-pager"}
if opts.UserMode {
args = append(args, "--user")
}
stdout, stderr, _, err := execute(ctx, args)
if err != nil {
return []Unit{}, errors.Join(err, filterErr(stderr))
}
lines := strings.Split(stdout, "\n")
units := []Unit{}
for _, line := range lines {
entry := strings.Fields(line)
if len(entry) < 4 {
continue
}
unit := Unit{
Name: entry[0],
Load: entry[1],
Active: entry[2],
Sub: entry[3],
Description: strings.Join(entry[4:], " "),
}
units = append(units, unit)
}
return units, nil
}
func GetMaskedUnits(ctx context.Context, opts Options) ([]string, error) {
args := []string{"list-unit-files", "--state=masked"}
if opts.UserMode {
args = append(args, "--user")
}
stdout, stderr, _, err := execute(ctx, args)
if err != nil {
return []string{}, errors.Join(err, filterErr(stderr))
}
lines := strings.Split(stdout, "\n")
units := []string{}
for _, line := range lines {
if !strings.Contains(line, "masked") {
continue
}
entry := strings.Split(line, " ")
if len(entry) < 3 {
continue
}
if entry[1] == "masked" {
unit := entry[0]
uName := strings.Split(unit, ".")
unit = uName[0]
units = append(units, unit)
}
}
return units, nil
}
// check if a service is masked
func IsMasked(ctx context.Context, unit string, opts Options) (bool, error) {
units, err := GetMaskedUnits(ctx, opts)
if err != nil {
return false, err
}
for _, u := range units {
if u == unit {
return true, nil
}
}
return false, nil
}
// check if a service is running
// https://unix.stackexchange.com/a/396633
func IsRunning(ctx context.Context, unit string, opts Options) (bool, error) {
status, err := Show(ctx, unit, properties.SubState, opts)
return status == "running", err
}