I have a C program that runs via systemd socket activation. Systemd listens on a port and when a TCP connections comes in, then the application is launched and it treats stdin/stdout exactly like a socket (IE: setsockopt, etc) .
I am trying to mimic this behavior with a small launching program in go. It will just be told what port to listen on and what command to run when a connection is made to it (none of the other advanced systemd features).
The problem I am having is that I don't seem to be able to pass the connection as a socket to stdin/out. Passing the TCPConn to Stdin
and Stdout
of the Cmd
did not work (the C program errored on setsockopts).
cmd := exec.Cmd{
Path: cmds,
Args: args,
Stdin: conn.,
Stdout: conn,
Stderr: os.Stderr,
}
err = cmd.Run()
I saw an article on how to do something like this in C using dup(2)
and fork, but
- it is forking not exec-ing another child process
- I don't entirely understand with the socket fd is being duplicated and not the
client
accepted connection
Is there any way to do something like this in Golang?
aditional info
the socket file looks roughly like
[Unit]
Description=soc activated program
[Socket]
ListenStream=0.0.0.0:10101
Accept=yes
[Install]
WantedBy=sockets.target
and corresponding unit file looks like:
[Unit]
Description=My Program
[Service]
Type=simple
ExecStart=/usr/bin/myprog -N
StandardInput=socket
StandardOutput=socket
StandardError=journal
TimeoutStopSec=5
KillMode=process
[Install]
WantedBy=multi-user.target
CodePudding user response:
Use the connections's file:
f, err := conn.File()
if err != nil { /* TODO handle error */}
defer f.Close()
cmd := exec.Cmd{
Path: cmds,
Args: args,
Stdin: f,
Stdout: f,
Stderr: os.Stderr,
}
err = cmd.Run()