I have a go binary that gets display information using cmd := exec.Command("xdpyinfo") then calling cmd.Output().
The program runs as expected in the terminal. However, when I run this as a systemd service there's no output from cmd.Output().
I'm program is running as a service, but calling cmd.Output() is returning an error.
I've tried to make this as easy to reproduce as possible:
I have a executable go binary named test at /home/myusername/Projects/test
The binary was built using go build from a single main.go file containing the following code:
package main
import (
"fmt"
"log"
"log/syslog"
"os/exec"
)
func main() {
logwriter, e := syslog.New(syslog.LOG_NOTICE, "testprog")
if e == nil {
log.SetOutput(logwriter)
}
cmd := exec.Command("xdpyinfo")
out, err := cmd.Output()
if err != nil {
log.Print(fmt.Errorf("ERROR: %v", err))
}
log.Print(string(out))
}
The logging is just for test purposes as the real code is part of a larger app.
When I run the test binary in the terminal I see the expected output from xdpyinfo in the logs.
However, when try to run the same binary in a service it outputs ERROR: exit status 1.
Steps I took to run the service:
- Create a unit service file at
/etc/systemd/system/TestProg.service:
[Unit]
Description=Test service
ConditionPathExists=/home/myusername/Projects/test/test
After=network.target
[Service]
Type=simple
Restart=on-failure
RestartSec=10
startLimitIntervalSec=60
WorkingDirectory=/home/myusername/Projects/test
ExecStart=/home/myusername/Projects/test/test
[Install]
WantedBy=multi-user.target
- Enable the service:
sudo systemctl enable TestProg.service
- Start the service:
sudo systemctl start TestProg.service
I've also tried locating the unit service file at /lib/systemd/system/TestProg.service and adding the User=username under Type=simple.
I've tried several different configurations to try and get this working. I've also tried setting the user using SysProcAttr (with actual uid and gid):
cmd := exec.Command("xdpyinfo")
cmd.SysProcAttr = &syscall.SysProcAttr{
Credential: &syscall.Credential{
Uid: uint32(uid),
Gid: uint32(gid),
NoSetGroups: true,
},
}
out, err := cmd.Output()
if err != nil {
log.Print(fmt.Errorf("ERROR: %v", err))
}
I'm now starting to think I'm missing something more fundamental.