summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/podman/main.go2
-rw-r--r--libpod/runtime.go42
-rw-r--r--pkg/rootless/rootless_linux.go88
-rw-r--r--pkg/rootless/rootless_unsupported.go6
4 files changed, 111 insertions, 27 deletions
diff --git a/cmd/podman/main.go b/cmd/podman/main.go
index 04b1e80cf..435efd559 100644
--- a/cmd/podman/main.go
+++ b/cmd/podman/main.go
@@ -100,7 +100,7 @@ func initConfig() {
}
func before(cmd *cobra.Command, args []string) error {
- if err := libpod.SetXdgRuntimeDir(""); err != nil {
+ if err := libpod.SetXdgRuntimeDir(); err != nil {
logrus.Errorf(err.Error())
os.Exit(1)
}
diff --git a/libpod/runtime.go b/libpod/runtime.go
index c0f49c468..5a618f592 100644
--- a/libpod/runtime.go
+++ b/libpod/runtime.go
@@ -10,6 +10,7 @@ import (
"strings"
"sync"
"syscall"
+ "time"
"github.com/BurntSushi/toml"
is "github.com/containers/image/storage"
@@ -312,18 +313,39 @@ func defaultRuntimeConfig() (RuntimeConfig, error) {
// SetXdgRuntimeDir ensures the XDG_RUNTIME_DIR env variable is set
// containers/image uses XDG_RUNTIME_DIR to locate the auth file.
-func SetXdgRuntimeDir(val string) error {
+// It internally calls EnableLinger() so that the user's processes are not
+// killed once the session is terminated. EnableLinger() also attempts to
+// get the runtime directory when XDG_RUNTIME_DIR is not specified.
+func SetXdgRuntimeDir() error {
if !rootless.IsRootless() {
return nil
}
- if val == "" {
+
+ runtimeDir := os.Getenv("XDG_RUNTIME_DIR")
+
+ runtimeDirLinger, err := rootless.EnableLinger()
+ if err != nil {
+ return errors.Wrapf(err, "error enabling user session")
+ }
+ if runtimeDir == "" && runtimeDirLinger != "" {
+ if _, err := os.Stat(runtimeDirLinger); err != nil && os.IsNotExist(err) {
+ chWait := make(chan error)
+ defer close(chWait)
+ if _, err := WaitForFile(runtimeDirLinger, chWait, time.Second*10); err != nil {
+ return errors.Wrapf(err, "waiting for directory '%s'", runtimeDirLinger)
+ }
+ }
+ runtimeDir = runtimeDirLinger
+ }
+
+ if runtimeDir == "" {
var err error
- val, err = util.GetRootlessRuntimeDir()
+ runtimeDir, err = util.GetRootlessRuntimeDir()
if err != nil {
return err
}
}
- if err := os.Setenv("XDG_RUNTIME_DIR", val); err != nil {
+ if err := os.Setenv("XDG_RUNTIME_DIR", runtimeDir); err != nil {
return errors.Wrapf(err, "cannot set XDG_RUNTIME_DIR")
}
return nil
@@ -479,18 +501,6 @@ func newRuntimeFromConfig(ctx context.Context, userConfigPath string, options ..
runtime.config.SignaturePolicyPath = newPath
}
}
-
- runtimeDir, err := util.GetRootlessRuntimeDir()
- if err != nil {
- return nil, err
- }
-
- // containers/image uses XDG_RUNTIME_DIR to locate the auth file.
- // So make sure the env variable is set.
- if err := SetXdgRuntimeDir(runtimeDir); err != nil {
- return nil, errors.Wrapf(err, "cannot set XDG_RUNTIME_DIR")
- }
-
}
if userConfigPath != "" {
diff --git a/pkg/rootless/rootless_linux.go b/pkg/rootless/rootless_linux.go
index ca8faecbd..d51f32d68 100644
--- a/pkg/rootless/rootless_linux.go
+++ b/pkg/rootless/rootless_linux.go
@@ -9,14 +9,17 @@ import (
"os/exec"
gosignal "os/signal"
"os/user"
+ "path/filepath"
"runtime"
"strconv"
+ "strings"
"sync"
"syscall"
"unsafe"
"github.com/containers/storage/pkg/idtools"
"github.com/docker/docker/pkg/signal"
+ "github.com/godbus/dbus"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
@@ -198,24 +201,90 @@ func getUserNSFirstChild(fd uintptr) (*os.File, error) {
}
}
-func enableLinger(pausePid string) {
- if pausePid == "" {
- return
+// EnableLinger configures the system to not kill the user processes once the session
+// terminates
+func EnableLinger() (string, error) {
+ uid := fmt.Sprintf("%d", GetRootlessUID())
+
+ conn, err := dbus.SystemBus()
+ if err == nil {
+ defer conn.Close()
+ }
+
+ lingerEnabled := false
+
+ // If we have a D-BUS connection, attempt to read the LINGER property from it.
+ if conn != nil {
+ path := dbus.ObjectPath((fmt.Sprintf("/org/freedesktop/login1/user/_%s", uid)))
+ ret, err := conn.Object("org.freedesktop.login1", path).GetProperty("org.freedesktop.login1.User.Linger")
+ if err == nil && ret.Value().(bool) {
+ lingerEnabled = true
+ }
+ }
+
+ xdgRuntimeDir := os.Getenv("XDG_RUNTIME_DIR")
+ lingerFile := ""
+ if xdgRuntimeDir != "" && !lingerEnabled {
+ lingerFile = filepath.Join(xdgRuntimeDir, "libpod/linger")
+ _, err := os.Stat(lingerFile)
+ if err == nil {
+ lingerEnabled = true
+ }
}
- // If we are trying to write a pause pid file, make sure we can leave processes
- // running longer than the user session.
- err := exec.Command("loginctl", "enable-linger", fmt.Sprintf("%d", GetRootlessUID())).Run()
+
+ if !lingerEnabled {
+ // First attempt with D-BUS, if it fails, then attempt with "loginctl enable-linger"
+ if conn != nil {
+ o := conn.Object("org.freedesktop.login1", "/org/freedesktop/login1")
+ ret := o.Call("org.freedesktop.login1.Manager.SetUserLinger", 0, uint32(GetRootlessUID()), true, true)
+ if ret.Err == nil {
+ lingerEnabled = true
+ }
+ }
+ if !lingerEnabled {
+ err := exec.Command("loginctl", "enable-linger", uid).Run()
+ if err == nil {
+ lingerEnabled = true
+ } else {
+ logrus.Debugf("cannot run `loginctl enable-linger` for the current user: %v", err)
+ }
+ }
+ if lingerEnabled && lingerFile != "" {
+ f, err := os.Create(lingerFile)
+ if err == nil {
+ f.Close()
+ } else {
+ logrus.Debugf("could not create linger file: %v", err)
+ }
+ }
+ }
+
+ if !lingerEnabled {
+ return "", nil
+ }
+
+ // If we have a D-BUS connection, attempt to read the RUNTIME PATH from it.
+ if conn != nil {
+ path := dbus.ObjectPath((fmt.Sprintf("/org/freedesktop/login1/user/_%s", uid)))
+ ret, err := conn.Object("org.freedesktop.login1", path).GetProperty("org.freedesktop.login1.User.RuntimePath")
+ if err == nil {
+ return strings.Trim(ret.String(), "\"\n"), nil
+ }
+ }
+
+ // If XDG_RUNTIME_DIR is not set and the D-BUS call didn't work, try to get the runtime path with "loginctl"
+ output, err := exec.Command("loginctl", "-pRuntimePath", "show-user", uid).Output()
if err != nil {
- logrus.Warnf("cannot run `loginctl enable-linger` for the current user: %v", err)
+ logrus.Debugf("could not get RuntimePath using loginctl: %v", err)
+ return "", nil
}
+ return strings.Trim(strings.Replace(string(output), "RuntimePath=", "", -1), "\"\n"), nil
}
// joinUserAndMountNS re-exec podman in a new userNS and join the user and mount
// namespace of the specified PID without looking up its parent. Useful to join directly
// the conmon process.
func joinUserAndMountNS(pid uint, pausePid string) (bool, int, error) {
- enableLinger(pausePid)
-
if os.Geteuid() == 0 || os.Getenv("_CONTAINERS_USERNS_CONFIGURED") != "" {
return false, -1, nil
}
@@ -406,7 +475,6 @@ func becomeRootInUserNS(pausePid, fileToRead string, fileOutput *os.File) (bool,
// If podman was re-executed the caller needs to propagate the error code returned by the child
// process.
func BecomeRootInUserNS(pausePid string) (bool, int, error) {
- enableLinger(pausePid)
return becomeRootInUserNS(pausePid, "", nil)
}
diff --git a/pkg/rootless/rootless_unsupported.go b/pkg/rootless/rootless_unsupported.go
index c063adee5..52863580e 100644
--- a/pkg/rootless/rootless_unsupported.go
+++ b/pkg/rootless/rootless_unsupported.go
@@ -29,6 +29,12 @@ func GetRootlessGID() int {
return -1
}
+// EnableLinger configures the system to not kill the user processes once the session
+// terminates
+func EnableLinger() (string, error) {
+ return "", nil
+}
+
// TryJoinFromFilePaths attempts to join the namespaces of the pid files in paths.
// This is useful when there are already running containers and we
// don't have a pause process yet. We can use the paths to the conmon