From 75578aad61c1e9fae021223ece70cb83e3e2bcf2 Mon Sep 17 00:00:00 2001
From: Valentin Rothberg <rothberg@redhat.com>
Date: Sat, 22 Dec 2018 14:59:43 +0100
Subject: add container-init support

Add support for executing an init binary as PID 1 in a container to
forward signals and reap processes.  When the `--init` flag is set for
podman-create or podman-run, the init binary is bind-mounted to
`/dev/init` in the container and "/dev/init --" is prepended to the
container's command.

The default base path of the container-init binary is `/usr/libexec/podman`
while the default binary is catatonit [1].  This default can be changed
permanently via the `init_path` field in the `libpod.conf` configuration
file (which is recommended for packaging) or temporarily via the
`--init-path` flag of podman-create and podman-run.

[1] https://github.com/openSUSE/catatonit

Fixes: #1670
Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
---
 pkg/spec/createconfig.go | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

(limited to 'pkg')

diff --git a/pkg/spec/createconfig.go b/pkg/spec/createconfig.go
index 25f8cd7a1..ffc98e307 100644
--- a/pkg/spec/createconfig.go
+++ b/pkg/spec/createconfig.go
@@ -2,6 +2,7 @@ package createconfig
 
 import (
 	"encoding/json"
+	"fmt"
 	"net"
 	"os"
 	"strconv"
@@ -145,6 +146,36 @@ func (c *CreateConfig) CreateBlockIO() (*spec.LinuxBlockIO, error) {
 	return c.createBlockIO()
 }
 
+// AddContainerInitBinary adds the init binary specified by path iff the
+// container will run in a private PID namespace that is not shared with the
+// host or another pre-existing container, where an init-like process is
+// already running.
+//
+// Note that AddContainerInitBinary prepends "/dev/init" "--" to the command
+// to execute the bind-mounted binary as PID 1.
+func (c *CreateConfig) AddContainerInitBinary(path string) error {
+	if path == "" {
+		return fmt.Errorf("please specify a path to the container-init binary")
+	}
+	if !c.PidMode.IsPrivate() {
+		return fmt.Errorf("cannot add init binary as PID 1 (PID namespace isn't private)")
+	}
+	if c.Systemd {
+		return fmt.Errorf("cannot use container-init binary with systemd")
+	}
+	if _, err := os.Stat(path); os.IsNotExist(err) {
+		return errors.Wrap(err, "container-init binary not found on the host")
+	}
+	c.Command = append([]string{"/dev/init", "--"}, c.Command...)
+	c.Mounts = append(c.Mounts, spec.Mount{
+		Destination: "/dev/init",
+		Type:        "bind",
+		Source:      path,
+		Options:     []string{"bind", "ro"},
+	})
+	return nil
+}
+
 func processOptions(options []string) []string {
 	var (
 		foundrw, foundro bool
-- 
cgit v1.2.3-54-g00ecf