summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/podman/cliconfig/config.go1
-rw-r--r--cmd/podman/libpodruntime/runtime.go3
-rw-r--r--cmd/podman/main.go30
-rw-r--r--cmd/podman/pod.go47
-rw-r--r--cmd/podman/pod_rm.go14
-rw-r--r--cmd/podman/pod_stats.go5
-rw-r--r--cmd/podman/pod_stop.go14
-rw-r--r--cmd/podman/rm.go79
-rw-r--r--docs/libpod.conf.5.md4
-rw-r--r--docs/podman.1.md3
-rw-r--r--libpod/container_internal.go2
-rw-r--r--libpod/networking_linux.go13
-rw-r--r--libpod/options.go14
-rw-r--r--libpod/runtime.go2
-rw-r--r--libpod/runtime_img.go29
-rw-r--r--pkg/adapter/runtime.go40
-rw-r--r--pkg/adapter/runtime_remote.go7
-rw-r--r--pkg/rootless/rootless.go9
-rw-r--r--pkg/rootless/rootless_linux.go37
-rw-r--r--pkg/rootless/rootless_unsupported.go33
-rw-r--r--pkg/varlinkapi/system.go1
21 files changed, 362 insertions, 25 deletions
diff --git a/cmd/podman/cliconfig/config.go b/cmd/podman/cliconfig/config.go
index 7945cb6cb..d58964489 100644
--- a/cmd/podman/cliconfig/config.go
+++ b/cmd/podman/cliconfig/config.go
@@ -25,6 +25,7 @@ type MainFlags struct {
StorageOpts []string
Syslog bool
Trace bool
+ NetworkCmdPath string
Config string
CpuProfile string
diff --git a/cmd/podman/libpodruntime/runtime.go b/cmd/podman/libpodruntime/runtime.go
index 2b96f0c20..3faea493c 100644
--- a/cmd/podman/libpodruntime/runtime.go
+++ b/cmd/podman/libpodruntime/runtime.go
@@ -86,6 +86,9 @@ func getRuntime(c *cliconfig.PodmanCommand, renumber bool) (*libpod.Runtime, err
if c.Flags().Changed("tmpdir") {
options = append(options, libpod.WithTmpDir(c.GlobalFlags.TmpDir))
}
+ if c.Flags().Changed("network-cmd-path") {
+ options = append(options, libpod.WithNetworkCmdPath(c.GlobalFlags.NetworkCmdPath))
+ }
if c.Flags().Changed("cgroup-manager") {
options = append(options, libpod.WithCgroupManager(c.GlobalFlags.CGroupManager))
diff --git a/cmd/podman/main.go b/cmd/podman/main.go
index 7d4b650a9..bbeb72397 100644
--- a/cmd/podman/main.go
+++ b/cmd/podman/main.go
@@ -65,18 +65,23 @@ var cmdsNotRequiringRootless = map[*cobra.Command]bool{
_exportCommand: true,
//// `info` must be executed in an user namespace.
//// If this change, please also update libpod.refreshRootless()
- _loginCommand: true,
- _logoutCommand: true,
- _mountCommand: true,
- _killCommand: true,
- _pauseCommand: true,
- _restartCommand: true,
- _runCommand: true,
- _unpauseCommand: true,
- _searchCommand: true,
- _statsCommand: true,
- _stopCommand: true,
- _topCommand: true,
+ _loginCommand: true,
+ _logoutCommand: true,
+ _mountCommand: true,
+ _killCommand: true,
+ _pauseCommand: true,
+ _podRmCommand: true,
+ _podKillCommand: true,
+ _podStatsCommand: true,
+ _podStopCommand: true,
+ _restartCommand: true,
+ _rmCommand: true,
+ _runCommand: true,
+ _unpauseCommand: true,
+ _searchCommand: true,
+ _statsCommand: true,
+ _stopCommand: true,
+ _topCommand: true,
}
var rootCmd = &cobra.Command{
@@ -104,6 +109,7 @@ func init() {
rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.CpuProfile, "cpu-profile", "", "Path for the cpu profiling results")
rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.Config, "config", "", "Path of a libpod config file detailing container server configuration options")
rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.ConmonPath, "conmon", "", "Path of the conmon binary")
+ rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.NetworkCmdPath, "network-cmd-path", "", "Path to the command for configuring the network")
rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.CniConfigDir, "cni-config-dir", "", "Path of the configuration directory for CNI networks")
rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.DefaultMountsFile, "default-mounts-file", "", "Path to default mounts file")
rootCmd.PersistentFlags().MarkHidden("defaults-mount-file")
diff --git a/cmd/podman/pod.go b/cmd/podman/pod.go
index 2d9bca21d..9a9c7a702 100644
--- a/cmd/podman/pod.go
+++ b/cmd/podman/pod.go
@@ -1,7 +1,12 @@
package main
import (
+ "os"
+
"github.com/containers/libpod/cmd/podman/cliconfig"
+ "github.com/containers/libpod/pkg/adapter"
+ "github.com/containers/libpod/pkg/rootless"
+ "github.com/pkg/errors"
"github.com/spf13/cobra"
)
@@ -34,6 +39,48 @@ var podSubCommands = []*cobra.Command{
_podUnpauseCommand,
}
+func joinPodNS(runtime *adapter.LocalRuntime, all, latest bool, inputArgs []string) ([]string, bool, bool, error) {
+ if rootless.IsRootless() {
+ if os.Geteuid() == 0 {
+ return []string{rootless.Argument()}, false, false, nil
+ } else {
+ var err error
+ var pods []*adapter.Pod
+ if all {
+ pods, err = runtime.GetAllPods()
+ if err != nil {
+ return nil, false, false, errors.Wrapf(err, "unable to get pods")
+ }
+ } else if latest {
+ pod, err := runtime.GetLatestPod()
+ if err != nil {
+ return nil, false, false, errors.Wrapf(err, "unable to get latest pod")
+ }
+ pods = append(pods, pod)
+ } else {
+ for _, i := range inputArgs {
+ pod, err := runtime.LookupPod(i)
+ if err != nil {
+ return nil, false, false, errors.Wrapf(err, "unable to lookup pod %s", i)
+ }
+ pods = append(pods, pod)
+ }
+ }
+ for _, p := range pods {
+ _, ret, err := runtime.JoinOrCreateRootlessPod(p)
+ if err != nil {
+ return nil, false, false, err
+ }
+ if ret != 0 {
+ os.Exit(ret)
+ }
+ }
+ os.Exit(0)
+ }
+ }
+ return inputArgs, all, latest, nil
+}
+
func init() {
podCommand.AddCommand(podSubCommands...)
podCommand.SetHelpTemplate(HelpTemplate())
diff --git a/cmd/podman/pod_rm.go b/cmd/podman/pod_rm.go
index a40992818..735676f8a 100644
--- a/cmd/podman/pod_rm.go
+++ b/cmd/podman/pod_rm.go
@@ -2,9 +2,11 @@ package main
import (
"fmt"
+ "os"
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/pkg/adapter"
+ "github.com/containers/libpod/pkg/rootless"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
@@ -46,11 +48,23 @@ func init() {
// podRmCmd deletes pods
func podRmCmd(c *cliconfig.PodRmValues) error {
+ if os.Geteuid() != 0 {
+ rootless.SetSkipStorageSetup(true)
+ }
runtime, err := adapter.GetRuntime(&c.PodmanCommand)
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
defer runtime.Shutdown(false)
+
+ if rootless.IsRootless() {
+ var err error
+ c.InputArgs, c.All, c.Latest, err = joinPodNS(runtime, c.All, c.Latest, c.InputArgs)
+ if err != nil {
+ return err
+ }
+ }
+
podRmIds, podRmErrors := runtime.RemovePods(getContext(), c)
for _, p := range podRmIds {
fmt.Println(p)
diff --git a/cmd/podman/pod_stats.go b/cmd/podman/pod_stats.go
index 7dbd84525..5c30e0595 100644
--- a/cmd/podman/pod_stats.go
+++ b/cmd/podman/pod_stats.go
@@ -53,6 +53,11 @@ func init() {
}
func podStatsCmd(c *cliconfig.PodStatsValues) error {
+
+ if os.Geteuid() != 0 {
+ return errors.New("stats is not supported in rootless mode")
+ }
+
format := c.Format
all := c.All
latest := c.Latest
diff --git a/cmd/podman/pod_stop.go b/cmd/podman/pod_stop.go
index f1b0ac51f..754a3a7db 100644
--- a/cmd/podman/pod_stop.go
+++ b/cmd/podman/pod_stop.go
@@ -2,9 +2,11 @@ package main
import (
"fmt"
+ "os"
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/pkg/adapter"
+ "github.com/containers/libpod/pkg/rootless"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
@@ -46,12 +48,24 @@ func init() {
}
func podStopCmd(c *cliconfig.PodStopValues) error {
+ if os.Geteuid() != 0 {
+ rootless.SetSkipStorageSetup(true)
+ }
+
runtime, err := adapter.GetRuntime(&c.PodmanCommand)
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
defer runtime.Shutdown(false)
+ if rootless.IsRootless() {
+ var err error
+ c.InputArgs, c.All, c.Latest, err = joinPodNS(runtime, c.All, c.Latest, c.InputArgs)
+ if err != nil {
+ return err
+ }
+ }
+
podStopIds, podStopErrors := runtime.StopPods(getContext(), c)
for _, p := range podStopIds {
fmt.Println(p)
diff --git a/cmd/podman/rm.go b/cmd/podman/rm.go
index 4230bb396..56aaae9eb 100644
--- a/cmd/podman/rm.go
+++ b/cmd/podman/rm.go
@@ -2,12 +2,16 @@ package main
import (
"fmt"
+ "io/ioutil"
+ "os"
+ "strconv"
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/libpodruntime"
"github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/image"
+ "github.com/containers/libpod/pkg/rootless"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
@@ -48,11 +52,39 @@ func init() {
markFlagHiddenForRemoteClient("latest", flags)
}
+func joinContainerOrCreateRootlessUserNS(runtime *libpod.Runtime, ctr *libpod.Container) (bool, int, error) {
+ if os.Geteuid() == 0 {
+ return false, 0, nil
+ }
+ s, err := ctr.State()
+ if err != nil {
+ return false, -1, err
+ }
+ opts := rootless.Opts{
+ Argument: ctr.ID(),
+ }
+ if s == libpod.ContainerStateRunning || s == libpod.ContainerStatePaused {
+ data, err := ioutil.ReadFile(ctr.Config().ConmonPidFile)
+ if err != nil {
+ return false, -1, errors.Wrapf(err, "cannot read conmon PID file %q", ctr.Config().ConmonPidFile)
+ }
+ conmonPid, err := strconv.Atoi(string(data))
+ if err != nil {
+ return false, -1, errors.Wrapf(err, "cannot parse PID %q", data)
+ }
+ return rootless.JoinDirectUserAndMountNSWithOpts(uint(conmonPid), &opts)
+ }
+ return rootless.BecomeRootInUserNSWithOpts(&opts)
+}
+
// saveCmd saves the image to either docker-archive or oci
func rmCmd(c *cliconfig.RmValues) error {
var (
deleteFuncs []shared.ParallelWorkerInput
)
+ if os.Geteuid() != 0 {
+ rootless.SetSkipStorageSetup(true)
+ }
ctx := getContext()
runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand)
@@ -61,6 +93,53 @@ func rmCmd(c *cliconfig.RmValues) error {
}
defer runtime.Shutdown(false)
+ if rootless.IsRootless() {
+ // When running in rootless mode we cannot manage different containers and
+ // user namespaces from the same context, so be sure to re-exec once for each
+ // container we are dealing with.
+ // What we do is to first collect all the containers we want to delete, then
+ // we re-exec in each of the container namespaces and from there remove the single
+ // container.
+ var container *libpod.Container
+ if os.Geteuid() == 0 {
+ // We are in the namespace, override InputArgs with the single
+ // argument that was passed down to us.
+ c.All = false
+ c.Latest = false
+ c.InputArgs = []string{rootless.Argument()}
+ } else {
+ var containers []*libpod.Container
+ if c.All {
+ containers, err = runtime.GetContainers()
+ } else if c.Latest {
+ container, err = runtime.GetLatestContainer()
+ if err != nil {
+ return errors.Wrapf(err, "unable to get latest pod")
+ }
+ containers = append(containers, container)
+ } else {
+ for _, c := range c.InputArgs {
+ container, err = runtime.LookupContainer(c)
+ if err != nil {
+ return err
+ }
+ containers = append(containers, container)
+ }
+ }
+ // Now we really delete the containers.
+ for _, c := range containers {
+ _, ret, err := joinContainerOrCreateRootlessUserNS(runtime, c)
+ if err != nil {
+ return err
+ }
+ if ret != 0 {
+ os.Exit(ret)
+ }
+ }
+ os.Exit(0)
+ }
+ }
+
failureCnt := 0
delContainers, err := getAllOrLatestContainers(&c.PodmanCommand, runtime, -1, "all")
if err != nil {
diff --git a/docs/libpod.conf.5.md b/docs/libpod.conf.5.md
index 9a19e1224..777edeacb 100644
--- a/docs/libpod.conf.5.md
+++ b/docs/libpod.conf.5.md
@@ -91,6 +91,10 @@ libpod to manage containers.
Directory where named volumes will be created in using the default volume driver.
By default this will be configured relative to where containers/storage stores containers.
+**network_cmd_path**=""
+ Path to the command binary to use for setting up a network. It is currently only used for setting up
+ a slirp4netns network. If "" is used then the binary is looked up using the $PATH environment variable.
+
## FILES
`/usr/share/containers/libpod.conf`, default libpod configuration path
diff --git a/docs/podman.1.md b/docs/podman.1.md
index 5c930995c..0182690d0 100644
--- a/docs/podman.1.md
+++ b/docs/podman.1.md
@@ -72,6 +72,9 @@ Default state dir is configured in /etc/containers/storage.conf.
Name of the OCI runtime as specified in libpod.conf or absolute path to the OCI compatible binary used to run containers.
+**--network-cmd-path**=**path**
+Path to the command binary to use for setting up a network. It is currently only used for setting up a slirp4netns network. If "" is used then the binary is looked up using the $PATH environment variable.
+
**--storage-driver**=**value**
Storage driver. The default storage driver for UID 0 is configured in /etc/containers/storage.conf (`$HOME/.config/containers/storage.conf` in rootless mode), and is *vfs* for non-root users when *fuse-overlayfs* is not available. The `STORAGE_DRIVER` environment variable overrides the default. The --storage-driver specified driver overrides all.
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index d86062e38..00e6786f9 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -1086,7 +1086,7 @@ func (c *Container) cleanupStorage() error {
// error
// We still want to be able to kick the container out of the
// state
- if err == storage.ErrNotAContainer || err == storage.ErrContainerUnknown {
+ if errors.Cause(err) == storage.ErrNotAContainer || errors.Cause(err) == storage.ErrContainerUnknown {
logrus.Errorf("Storage for container %s has been removed", c.ID())
return nil
}
diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go
index f9caf26d1..80d7d8213 100644
--- a/libpod/networking_linux.go
+++ b/libpod/networking_linux.go
@@ -139,10 +139,15 @@ func (r *Runtime) setupRootlessNetNS(ctr *Container) (err error) {
defer ctr.rootlessSlirpSyncR.Close()
defer ctr.rootlessSlirpSyncW.Close()
- path, err := exec.LookPath("slirp4netns")
- if err != nil {
- logrus.Errorf("could not find slirp4netns, the network namespace won't be configured: %v", err)
- return nil
+ path := r.config.NetworkCmdPath
+
+ if path == "" {
+ var err error
+ path, err = exec.LookPath("slirp4netns")
+ if err != nil {
+ logrus.Errorf("could not find slirp4netns, the network namespace won't be configured: %v", err)
+ return nil
+ }
}
syncR, syncW, err := os.Pipe()
diff --git a/libpod/options.go b/libpod/options.go
index 5ad2824d9..64b425c57 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -193,6 +193,20 @@ func WithConmonEnv(environment []string) RuntimeOption {
}
}
+// WithNetworkCmdPath specifies the path to the slirp4netns binary which manages the
+// runtime.
+func WithNetworkCmdPath(path string) RuntimeOption {
+ return func(rt *Runtime) error {
+ if rt.valid {
+ return ErrRuntimeFinalized
+ }
+
+ rt.config.NetworkCmdPath = path
+
+ return nil
+ }
+}
+
// WithCgroupManager specifies the manager implementation name which is used to
// handle cgroups for containers.
// Current valid values are "cgroupfs" and "systemd".
diff --git a/libpod/runtime.go b/libpod/runtime.go
index 9667abfe6..535b6f41b 100644
--- a/libpod/runtime.go
+++ b/libpod/runtime.go
@@ -217,6 +217,8 @@ type RuntimeConfig struct {
EnablePortReservation bool `toml:"enable_port_reservation"`
// EnableLabeling indicates wether libpod will support container labeling
EnableLabeling bool `toml:"label"`
+ // NetworkCmdPath is the path to the slirp4netns binary
+ NetworkCmdPath string `toml:"network_cmd_path"`
// NumLocks is the number of locks to make available for containers and
// pods.
diff --git a/libpod/runtime_img.go b/libpod/runtime_img.go
index 451c2ebe7..02f925fc6 100644
--- a/libpod/runtime_img.go
+++ b/libpod/runtime_img.go
@@ -14,6 +14,7 @@ import (
"github.com/containers/libpod/pkg/util"
"github.com/containers/storage"
"github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
"github.com/containers/image/directory"
dockerarchive "github.com/containers/image/docker/archive"
@@ -183,6 +184,15 @@ func (r *Runtime) Import(ctx context.Context, source string, reference string, c
defer os.Remove(file)
source = file
}
+ // if it's stdin, buffer it, too
+ if source == "-" {
+ file, err := downloadFromFile(os.Stdin)
+ if err != nil {
+ return "", err
+ }
+ defer os.Remove(file)
+ source = file
+ }
newImage, err := r.imageRuntime.Import(ctx, source, reference, writer, image.SigningOptions{}, config)
if err != nil {
@@ -216,6 +226,25 @@ func downloadFromURL(source string) (string, error) {
return outFile.Name(), nil
}
+// donwloadFromFile reads all of the content from the reader and temporarily
+// saves in it /var/tmp/importxyz, which is deleted after the image is imported
+func downloadFromFile(reader *os.File) (string, error) {
+ outFile, err := ioutil.TempFile("/var/tmp", "import")
+ if err != nil {
+ return "", errors.Wrap(err, "error creating file")
+ }
+ defer outFile.Close()
+
+ logrus.Debugf("saving %s to %s", reader.Name(), outFile.Name())
+
+ _, err = io.Copy(outFile, reader)
+ if err != nil {
+ return "", errors.Wrapf(err, "error saving %s to %s", reader.Name(), outFile.Name())
+ }
+
+ return outFile.Name(), nil
+}
+
// LoadImage loads a container image into local storage
func (r *Runtime) LoadImage(ctx context.Context, name, inputFile string, writer io.Writer, signaturePolicy string) (string, error) {
var newImages []*image.Image
diff --git a/pkg/adapter/runtime.go b/pkg/adapter/runtime.go
index 732b89530..482b6119a 100644
--- a/pkg/adapter/runtime.go
+++ b/pkg/adapter/runtime.go
@@ -337,3 +337,43 @@ func IsImageNotFound(err error) bool {
func (r *LocalRuntime) HealthCheck(c *cliconfig.HealthCheckValues) (libpod.HealthCheckStatus, error) {
return r.Runtime.HealthCheck(c.InputArgs[0])
}
+
+// JoinOrCreateRootlessPod joins the specified pod if it is running or it creates a new user namespace
+// if the pod is stopped
+func (r *LocalRuntime) JoinOrCreateRootlessPod(pod *Pod) (bool, int, error) {
+ if os.Geteuid() == 0 {
+ return false, 0, nil
+ }
+ opts := rootless.Opts{
+ Argument: pod.ID(),
+ }
+
+ inspect, err := pod.Inspect()
+ if err != nil {
+ return false, 0, err
+ }
+ for _, ctr := range inspect.Containers {
+ prevCtr, err := r.LookupContainer(ctr.ID)
+ if err != nil {
+ return false, -1, err
+ }
+ s, err := prevCtr.State()
+ if err != nil {
+ return false, -1, err
+ }
+ if s != libpod.ContainerStateRunning && s != libpod.ContainerStatePaused {
+ continue
+ }
+ data, err := ioutil.ReadFile(prevCtr.Config().ConmonPidFile)
+ if err != nil {
+ return false, -1, errors.Wrapf(err, "cannot read conmon PID file %q", prevCtr.Config().ConmonPidFile)
+ }
+ conmonPid, err := strconv.Atoi(string(data))
+ if err != nil {
+ return false, -1, errors.Wrapf(err, "cannot parse PID %q", data)
+ }
+ return rootless.JoinDirectUserAndMountNSWithOpts(uint(conmonPid), &opts)
+ }
+
+ return rootless.BecomeRootInUserNSWithOpts(&opts)
+}
diff --git a/pkg/adapter/runtime_remote.go b/pkg/adapter/runtime_remote.go
index 10c25c3f3..9ca4e245f 100644
--- a/pkg/adapter/runtime_remote.go
+++ b/pkg/adapter/runtime_remote.go
@@ -751,3 +751,10 @@ func IsImageNotFound(err error) bool {
func (r *LocalRuntime) HealthCheck(c *cliconfig.HealthCheckValues) (libpod.HealthCheckStatus, error) {
return -1, libpod.ErrNotImplemented
}
+
+// JoinOrCreateRootlessPod joins the specified pod if it is running or it creates a new user namespace
+// if the pod is stopped
+func (r *LocalRuntime) JoinOrCreateRootlessPod(pod *Pod) (bool, int, error) {
+ // Nothing to do in the remote case
+ return true, 0, nil
+}
diff --git a/pkg/rootless/rootless.go b/pkg/rootless/rootless.go
new file mode 100644
index 000000000..a531e43ce
--- /dev/null
+++ b/pkg/rootless/rootless.go
@@ -0,0 +1,9 @@
+package rootless
+
+// Opts allows to customize how re-execing to a rootless process is done
+type Opts struct {
+ // Argument overrides the arguments on the command line
+ // for the re-execed process. The process in the namespace
+ // must use rootless.Argument() to read its value.
+ Argument string
+}
diff --git a/pkg/rootless/rootless_linux.go b/pkg/rootless/rootless_linux.go
index d43151e8e..b2677f7d9 100644
--- a/pkg/rootless/rootless_linux.go
+++ b/pkg/rootless/rootless_linux.go
@@ -60,6 +60,11 @@ func SkipStorageSetup() bool {
return skipStorageSetup
}
+// Argument returns the argument that was set for the rootless session.
+func Argument() string {
+ return os.Getenv("_LIBPOD_ROOTLESS_ARG")
+}
+
// GetRootlessUID returns the UID of the user in the parent userNS
func GetRootlessUID() int {
uidEnv := os.Getenv("_LIBPOD_ROOTLESS_UID")
@@ -134,8 +139,16 @@ func JoinNS(pid uint, preserveFDs int) (bool, int, error) {
// JoinDirectUserAndMountNS 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.
+// the conmon process. It is a convenience function for JoinDirectUserAndMountNSWithOpts
+// with a default configuration.
func JoinDirectUserAndMountNS(pid uint) (bool, int, error) {
+ return JoinDirectUserAndMountNSWithOpts(pid, nil)
+}
+
+// JoinDirectUserAndMountNSWithOpts 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 JoinDirectUserAndMountNSWithOpts(pid uint, opts *Opts) (bool, int, error) {
if os.Geteuid() == 0 || os.Getenv("_LIBPOD_USERNS_CONFIGURED") != "" {
return false, -1, nil
}
@@ -152,6 +165,12 @@ func JoinDirectUserAndMountNS(pid uint) (bool, int, error) {
}
defer userNS.Close()
+ if opts != nil && opts.Argument != "" {
+ if err := os.Setenv("_LIBPOD_ROOTLESS_ARG", opts.Argument); err != nil {
+ return false, -1, err
+ }
+ }
+
pidC := C.reexec_userns_join(C.int(userNS.Fd()), C.int(mountNS.Fd()))
if int(pidC) < 0 {
return false, -1, errors.Errorf("cannot re-exec process")
@@ -194,8 +213,16 @@ func JoinNSPath(path string) (bool, int, error) {
// BecomeRootInUserNS re-exec podman in a new userNS. It returns whether podman was re-executed
// into a new user namespace and the return code from the re-executed podman process.
// If podman was re-executed the caller needs to propagate the error code returned by the child
-// process.
+// process. It is a convenience function for BecomeRootInUserNSWithOpts with a default configuration.
func BecomeRootInUserNS() (bool, int, error) {
+ return BecomeRootInUserNSWithOpts(nil)
+}
+
+// BecomeRootInUserNSWithOpts re-exec podman in a new userNS. It returns whether podman was
+// re-execute into a new user namespace and the return code from the re-executed podman process.
+// If podman was re-executed the caller needs to propagate the error code returned by the child
+// process.
+func BecomeRootInUserNSWithOpts(opts *Opts) (bool, int, error) {
if os.Geteuid() == 0 || os.Getenv("_LIBPOD_USERNS_CONFIGURED") != "" {
if os.Getenv("_LIBPOD_USERNS_CONFIGURED") == "init" {
return false, 0, runInUser()
@@ -214,6 +241,12 @@ func BecomeRootInUserNS() (bool, int, error) {
defer w.Close()
defer w.Write([]byte("0"))
+ if opts != nil && opts.Argument != "" {
+ if err := os.Setenv("_LIBPOD_ROOTLESS_ARG", opts.Argument); err != nil {
+ return false, -1, err
+ }
+ }
+
pidC := C.reexec_in_user_namespace(C.int(r.Fd()))
pid := int(pidC)
if pid < 0 {
diff --git a/pkg/rootless/rootless_unsupported.go b/pkg/rootless/rootless_unsupported.go
index 1823c023e..54e70961b 100644
--- a/pkg/rootless/rootless_unsupported.go
+++ b/pkg/rootless/rootless_unsupported.go
@@ -11,10 +11,18 @@ func IsRootless() bool {
return false
}
+// BecomeRootInUserNS re-exec podman in a new userNS. It returns whether podman was re-executed
+// into a new user namespace and the return code from the re-executed podman process.
+// If podman was re-executed the caller needs to propagate the error code returned by the child
+// process. It is a convenience function for BecomeRootInUserNSWithOpts with a default configuration.
+func BecomeRootInUserNS() (bool, int, error) {
+ return false, -1, errors.New("this function is not supported on this os")
+}
+
// BecomeRootInUserNS is a stub function that always returns false and an
// error on unsupported OS's
-func BecomeRootInUserNS() (bool, int, error) {
- return false, -1, errors.New("this function is not supported on this os1")
+func BecomeRootInUserNSWithOpts(opts *Opts) (bool, int, error) {
+ return false, -1, errors.New("this function is not supported on this os")
}
// GetRootlessUID returns the UID of the user in the parent userNS
@@ -34,18 +42,31 @@ func SkipStorageSetup() bool {
// JoinNS re-exec podman in a new userNS and join the user namespace of the specified
// PID.
func JoinNS(pid uint) (bool, int, error) {
- return false, -1, errors.New("this function is not supported on this os2")
+ return false, -1, errors.New("this function is not supported on this os")
}
// JoinNSPath re-exec podman in a new userNS and join the owner user namespace of the
// specified path.
func JoinNSPath(path string) (bool, int, error) {
- return false, -1, errors.New("this function is not supported on this os3")
+ return false, -1, errors.New("this function is not supported on this os")
+}
+
+// JoinDirectUserAndMountNSWithOpts 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 JoinDirectUserAndMountNSWithOpts(pid uint, opts *Opts) (bool, int, error) {
+ return false, -1, errors.New("this function is not supported on this os")
}
// JoinDirectUserAndMountNS 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.
+// the conmon process. It is a convenience function for JoinDirectUserAndMountNSWithOpts
+// with a default configuration.
func JoinDirectUserAndMountNS(pid uint) (bool, int, error) {
- return false, -1, errors.New("this function is not supported on this os4")
+ return false, -1, errors.New("this function is not supported on this os")
+}
+
+// Argument returns the argument that was set for the rootless session.
+func Argument() string {
+ return ""
}
diff --git a/pkg/varlinkapi/system.go b/pkg/varlinkapi/system.go
index 3f32615ec..816143e9f 100644
--- a/pkg/varlinkapi/system.go
+++ b/pkg/varlinkapi/system.go
@@ -52,6 +52,7 @@ func (i *LibpodAPI) GetInfo(call iopodman.VarlinkCall) error {
Mem_free: host["MemFree"].(int64),
Mem_total: host["MemTotal"].(int64),
Swap_free: host["SwapFree"].(int64),
+ Swap_total: host["SwapTotal"].(int64),
Arch: host["arch"].(string),
Cpus: int64(host["cpus"].(int)),
Hostname: host["hostname"].(string),