incus-mirror/cmd/incus/exec_unix.go
Stéphane Graber 3473bbe61c
incus: Log deferred errors with WarnOnError
Signed-off-by: Stéphane Graber <stgraber@stgraber.org>
2026-06-06 19:14:35 -04:00

173 lines
4.6 KiB
Go

//go:build !windows
package main
import (
"os"
"os/signal"
"github.com/gorilla/websocket"
"golang.org/x/sys/unix"
"github.com/lxc/incus/v7/shared/api"
"github.com/lxc/incus/v7/shared/logger"
)
func (c *cmdExec) getTERM() (string, bool) {
return os.LookupEnv("TERM")
}
func (c *cmdExec) controlSocketHandler(control *websocket.Conn) {
ch := make(chan os.Signal, 10)
signal.Notify(ch,
unix.SIGWINCH,
unix.SIGTERM,
unix.SIGHUP,
unix.SIGINT,
unix.SIGQUIT,
unix.SIGABRT,
unix.SIGTSTP,
unix.SIGTTIN,
unix.SIGTTOU,
unix.SIGUSR1,
unix.SIGUSR2,
unix.SIGSEGV,
unix.SIGCONT)
closeMsg := websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")
defer logger.WarnOnError(func() error { return control.WriteMessage(websocket.CloseMessage, closeMsg) }, "Failed to write close message")
for {
sig := <-ch
switch sig {
case unix.SIGWINCH:
if !c.interactive {
// Don't send SIGWINCH to non-interactive, this can lead to console corruption/crashes.
continue
}
logger.Debugf("Received '%s signal', updating window geometry.", sig)
err := c.sendTermSize(control)
if err != nil {
logger.Debugf("error setting term size %s", err)
return
}
case unix.SIGTERM:
logger.Debugf("Received '%s signal', forwarding to executing program.", sig)
err := c.forwardSignal(control, unix.SIGTERM)
if err != nil {
logger.Debugf("Failed to forward signal '%s'.", unix.SIGTERM)
return
}
case unix.SIGHUP:
file, err := os.OpenFile("/dev/tty", os.O_RDONLY|unix.O_NOCTTY|unix.O_NOFOLLOW|unix.O_CLOEXEC, 0o666)
if err == nil {
_ = file.Close()
err = c.forwardSignal(control, unix.SIGHUP)
} else {
err = c.forwardSignal(control, unix.SIGTERM)
sig = unix.SIGTERM
}
logger.Debugf("Received '%s signal', forwarding to executing program.", sig)
if err != nil {
logger.Debugf("Failed to forward signal '%s'.", sig)
return
}
case unix.SIGINT:
logger.Debugf("Received '%s signal', forwarding to executing program.", sig)
err := c.forwardSignal(control, unix.SIGINT)
if err != nil {
logger.Debugf("Failed to forward signal '%s'.", unix.SIGINT)
return
}
case unix.SIGQUIT:
logger.Debugf("Received '%s signal', forwarding to executing program.", sig)
err := c.forwardSignal(control, unix.SIGQUIT)
if err != nil {
logger.Debugf("Failed to forward signal '%s'.", unix.SIGQUIT)
return
}
case unix.SIGABRT:
logger.Debugf("Received '%s signal', forwarding to executing program.", sig)
err := c.forwardSignal(control, unix.SIGABRT)
if err != nil {
logger.Debugf("Failed to forward signal '%s'.", unix.SIGABRT)
return
}
case unix.SIGTSTP:
logger.Debugf("Received '%s signal', forwarding to executing program.", sig)
err := c.forwardSignal(control, unix.SIGTSTP)
if err != nil {
logger.Debugf("Failed to forward signal '%s'.", unix.SIGTSTP)
return
}
case unix.SIGTTIN:
logger.Debugf("Received '%s signal', forwarding to executing program.", sig)
err := c.forwardSignal(control, unix.SIGTTIN)
if err != nil {
logger.Debugf("Failed to forward signal '%s'.", unix.SIGTTIN)
return
}
case unix.SIGTTOU:
logger.Debugf("Received '%s signal', forwarding to executing program.", sig)
err := c.forwardSignal(control, unix.SIGTTOU)
if err != nil {
logger.Debugf("Failed to forward signal '%s'.", unix.SIGTTOU)
return
}
case unix.SIGUSR1:
logger.Debugf("Received '%s signal', forwarding to executing program.", sig)
err := c.forwardSignal(control, unix.SIGUSR1)
if err != nil {
logger.Debugf("Failed to forward signal '%s'.", unix.SIGUSR1)
return
}
case unix.SIGUSR2:
logger.Debugf("Received '%s signal', forwarding to executing program.", sig)
err := c.forwardSignal(control, unix.SIGUSR2)
if err != nil {
logger.Debugf("Failed to forward signal '%s'.", unix.SIGUSR2)
return
}
case unix.SIGSEGV:
logger.Debugf("Received '%s signal', forwarding to executing program.", sig)
err := c.forwardSignal(control, unix.SIGSEGV)
if err != nil {
logger.Debugf("Failed to forward signal '%s'.", unix.SIGSEGV)
return
}
case unix.SIGCONT:
logger.Debugf("Received '%s signal', forwarding to executing program.", sig)
err := c.forwardSignal(control, unix.SIGCONT)
if err != nil {
logger.Debugf("Failed to forward signal '%s'.", unix.SIGCONT)
return
}
}
}
}
func (c *cmdExec) forwardSignal(control *websocket.Conn, sig unix.Signal) error {
logger.Debugf("Forwarding signal: %s", sig)
msg := api.InstanceExecControl{}
msg.Command = "signal"
msg.Signal = int(sig)
return control.WriteJSON(msg)
}