Skip to content

Commit 02282c4

Browse files
committed
launchd: enable running after user logs out
Change the launch agent domain from 'gui/<uid>' (tied to login session) to 'user/<uid>' (tied to user, but may run when logged out). To allow the agent to be loaded with this new domain, explicitly set the 'LimitLoadToSessionType' value in the generated plist to 'Background' (default value seems to be 'Aqua', corresponding to the logged in session i.e. 'gui/<uid>' domain). Signed-off-by: Victoria Dye <[email protected]>
1 parent 374758a commit 02282c4

File tree

2 files changed

+20
-8
lines changed

2 files changed

+20
-8
lines changed

internal/daemon/launchd.go

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,15 @@ func (p *plist) addKeyValue(key string, value any) {
5151
}
5252
}
5353

54-
const domainFormat string = "gui/%s"
54+
const domainFormat string = "user/%s"
5555

5656
const LaunchdServiceNotFoundErrorCode int = 113
5757

5858
type launchdConfig struct {
5959
DaemonConfig
60-
StdOut string
61-
StdErr string
60+
LimitLoadToSessionType string
61+
StdOut string
62+
StdErr string
6263
}
6364

6465
func (c *launchdConfig) toPlist() *plist {
@@ -68,6 +69,7 @@ func (c *launchdConfig) toPlist() *plist {
6869
}
6970
p.addKeyValue("Label", c.Label)
7071
p.addKeyValue("Program", c.Program)
72+
p.addKeyValue("LimitLoadToSessionType", c.LimitLoadToSessionType)
7173
p.addKeyValue("StandardOutPath", c.StdOut)
7274
p.addKeyValue("StandardErrorPath", c.StdErr)
7375

@@ -152,9 +154,10 @@ func (l *launchd) bootoutFile(domain string, filename string) error {
152154
func (l *launchd) Create(config *DaemonConfig, force bool) error {
153155
// Add launchd-specific config
154156
lConfig := &launchdConfig{
155-
DaemonConfig: *config,
156-
StdOut: "/dev/null",
157-
StdErr: "/dev/null",
157+
DaemonConfig: *config,
158+
LimitLoadToSessionType: "Background",
159+
StdOut: "/dev/null",
160+
StdErr: "/dev/null",
158161
}
159162

160163
// Generate the configuration

internal/daemon/launchd_test.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,9 @@ var launchdCreatePlistTests = []struct {
124124
"<key>Program</key>",
125125
fmt.Sprintf("<string>%s</string>", basicDaemonConfig.Program),
126126

127+
"<key>LimitLoadToSessionType</key>",
128+
"<string>Background</string>",
129+
127130
"<key>StandardOutPath</key>",
128131
"<string>/dev/null</string>",
129132

@@ -161,6 +164,9 @@ var launchdCreatePlistTests = []struct {
161164
"<key>Program</key>",
162165
"<string>/path/to/the/program with a space</string>",
163166

167+
"<key>LimitLoadToSessionType</key>",
168+
"<string>Background</string>",
169+
164170
"<key>StandardOutPath</key>",
165171
"<string>/dev/null</string>",
166172

@@ -195,6 +201,9 @@ var launchdCreatePlistTests = []struct {
195201
"<key>Program</key>",
196202
"<string>/path/to/the/program</string>",
197203

204+
"<key>LimitLoadToSessionType</key>",
205+
"<string>Background</string>",
206+
198207
"<key>StandardOutPath</key>",
199208
"<string>/dev/null</string>",
200209

@@ -359,7 +368,7 @@ func TestLaunchd_Start(t *testing.T) {
359368
t.Run("Calls correct launchctl command", func(t *testing.T) {
360369
testCommandExecutor.On("Run",
361370
"launchctl",
362-
[]string{"kickstart", fmt.Sprintf("gui/123/%s", basicDaemonConfig.Label)},
371+
[]string{"kickstart", fmt.Sprintf("user/123/%s", basicDaemonConfig.Label)},
363372
).Return(0, nil).Once()
364373

365374
err := launchd.Start(basicDaemonConfig.Label)
@@ -400,7 +409,7 @@ func TestLaunchd_Stop(t *testing.T) {
400409
t.Run("Calls correct launchctl command", func(t *testing.T) {
401410
testCommandExecutor.On("Run",
402411
"launchctl",
403-
[]string{"kill", "SIGINT", fmt.Sprintf("gui/123/%s", basicDaemonConfig.Label)},
412+
[]string{"kill", "SIGINT", fmt.Sprintf("user/123/%s", basicDaemonConfig.Label)},
404413
).Return(0, nil).Once()
405414

406415
err := launchd.Stop(basicDaemonConfig.Label)

0 commit comments

Comments
 (0)