-
Notifications
You must be signed in to change notification settings - Fork 251
/
gdm3.go
105 lines (98 loc) · 3.62 KB
/
gdm3.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
// package gdm3 provides functions for interfacing with Gnome Desktop Manager 3 on linux
package gdm3
import (
"fmt"
"regexp"
"strings"
"github.com/taskcluster/taskcluster/v44/workers/generic-worker/host"
)
var (
automaticLogin = regexp.MustCompile(`^\s*AutomaticLogin\s*=`)
automaticLoginEnable = regexp.MustCompile(`^\s*AutomaticLoginEnable\s*=`)
automaticLoginReplace = regexp.MustCompile(`^\s*AutomaticLogin\s*=\s*(\S*)\s*$`)
)
// AutoLogonUser interprets source as the contents of the gdm3 custom.conf
// file, and parses it to look for an auto login user, and returns it if found,
// otherwise it returns the empty string.
func AutoLogonUser(source []byte) (username string) {
iniFileLineHandler(source, func(section, line string) {
if section == "daemon" {
u := automaticLoginReplace.ReplaceAllString(line, "${1}")
if u != line {
username = u
return
}
}
})
return
}
// SetAutoLogin interprets source as the contents of the gdm3 custom.conf file,
// and returns an updated version of it with the automatic desktop login
// enabled for the user specified by username.
func SetAutoLogin(username string, source []byte) (output []byte) {
newLinesAdded := false
outputLines := []string{}
iniFileLineHandler(source, func(section, line string) {
switch section {
case "daemon":
switch {
case automaticLogin.MatchString(line):
// discard any lines that set AutomaticLogin
// log.Printf("Discarding %s", line)
case automaticLoginEnable.MatchString(line):
// discard any lines that set AutomaticLoginEnable
// log.Printf("Discarding %s", line)
default:
// retain all other lines
// log.Printf("Retaining %s", line)
outputLines = append(outputLines, line)
}
if !newLinesAdded {
// We've just entered [daemon] section, so set autologin settings
// immediately, and flag that we've done it, so we only add this once.
outputLines = append(
outputLines,
"# Set by generic-worker",
"AutomaticLoginEnable = true",
"AutomaticLogin = "+username,
"",
)
newLinesAdded = true
}
default:
// retain all lines of all other sections
outputLines = append(outputLines, line)
}
})
o := strings.Join(outputLines, "\n")
return []byte(o)
}
// InteractiveUsername attempts to determine which single user is currently
// logged into a gnome3 desktop session. If it doesn't find precisely one user,
// it returns an error, otherwise it returns the user it found.
func InteractiveUsername() (string, error) {
gnomeSessionUserList, err := host.CombinedOutput("/bin/bash", "-c", "PROCPS_USERLEN=20 /usr/bin/w -s | /bin/grep gnome-[s]ession | /usr/bin/cut -f1 -d' '")
if err != nil {
return "", fmt.Errorf("Cannot run command to determine the interactive user: %v", err)
}
lines := strings.Split(gnomeSessionUserList, "\n")
if len(lines) != 2 || lines[1] != "" {
return "", fmt.Errorf("Number of gnome session users is not exactly one - not sure which user is interactively logged on: %#v", lines)
}
return lines[0], nil
}
// iniFileLineHandler splits the ini file contents passed in data into lines
// separated by '\n' tracking which ini section each line is in. It then calls
// callback for each line in sequence, passing it the section name of the line
// and the raw line itself.
func iniFileLineHandler(data []byte, callback func(section, line string)) {
section := ""
lines := strings.Split(string(data), "\n")
for _, line := range lines {
trimmedLine := strings.TrimSpace(line)
if len(trimmedLine) > 1 && trimmedLine[0] == '[' && trimmedLine[len(trimmedLine)-1] == ']' {
section = trimmedLine[1 : len(trimmedLine)-1]
}
callback(section, line)
}
}