go-sandbox/container/container_init.go
2020-02-27 23:30:32 -05:00

94 lines
2.1 KiB
Go

package container
import (
"fmt"
"os"
"runtime"
"github.com/criyle/go-sandbox/pkg/unixsocket"
)
type containerServer struct {
socket *socket
containerConfig
}
// Init is called for container init process
// it will check if pid == 1, otherwise it is noop
// Init will do infinite loop on socket commands,
// and exits when at socket close, use it in init function
func Init() (err error) {
// noop if self is not container init process
// Notice: docker init is also 1, additional check for args[1] == init
if os.Getpid() != 1 || len(os.Args) != 2 || os.Args[1] != initArg {
return nil
}
// exit process (with whole container) upon exit this function
// possible reason:
// 1. socket broken (parent exit)
// 2. panic
// 3. undefined cmd (possible race condition)
defer func() {
if err := recover(); err != nil {
fmt.Fprintf(os.Stderr, "container_exit: panic: %v\n", err)
os.Exit(1)
}
if err != nil {
fmt.Fprintf(os.Stderr, "container_exit: %v\n", err)
os.Exit(1)
}
fmt.Fprintf(os.Stderr, "container_exit\n")
os.Exit(0)
}()
// limit container resource usage
runtime.GOMAXPROCS(containerMaxProc)
// new_container environment shared the socket at fd 3 (marked close_exec)
const defaultFd = 3
soc, err := unixsocket.NewSocket(defaultFd)
if err != nil {
return fmt.Errorf("container_init: failed to new socket %v", err)
}
// serve forever
cs := &containerServer{socket: newSocket(soc)}
return cs.serve()
}
func (c *containerServer) serve() error {
for {
cmd, msg, err := c.recvCmd()
if err != nil {
return fmt.Errorf("serve: recvCmd %v", err)
}
if err := c.handleCmd(cmd, msg); err != nil {
return fmt.Errorf("serve: failed to execute cmd %v", err)
}
}
}
func (c *containerServer) handleCmd(cmd *cmd, msg *unixsocket.Msg) error {
switch cmd.Cmd {
case cmdPing:
return c.handlePing()
case cmdConf:
return c.handleConf(cmd.ConfCmd)
case cmdOpen:
return c.handleOpen(cmd.OpenCmd)
case cmdDelete:
return c.handleDelete(cmd.DeleteCmd)
case cmdReset:
return c.handleReset()
case cmdExecve:
return c.handleExecve(cmd.ExecCmd, msg)
}
return fmt.Errorf("unknown command: %s", cmd.Cmd)
}