diff options
Diffstat (limited to 'cmd/podman/exec.go')
-rw-r--r-- | cmd/podman/exec.go | 70 |
1 files changed, 52 insertions, 18 deletions
diff --git a/cmd/podman/exec.go b/cmd/podman/exec.go index 4917fb606..a6afbf75a 100644 --- a/cmd/podman/exec.go +++ b/cmd/podman/exec.go @@ -2,23 +2,23 @@ package main import ( "fmt" - "github.com/containers/libpod/cmd/podman/cliconfig" - "github.com/spf13/cobra" + "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/parse" "github.com/containers/libpod/libpod" "github.com/containers/libpod/pkg/rootless" "github.com/pkg/errors" + "github.com/spf13/cobra" ) var ( execCommand cliconfig.ExecValues - execDescription = ` - podman exec - - Run a command in a running container + execDescription = `Execute the specified command inside a running container. ` _execCommand = &cobra.Command{ Use: "exec [flags] CONTAINER [COMMAND [ARG...]]", @@ -37,16 +37,18 @@ var ( func init() { execCommand.Command = _execCommand + execCommand.SetHelpTemplate(HelpTemplate()) execCommand.SetUsageTemplate(UsageTemplate()) flags := execCommand.Flags() flags.SetInterspersed(false) - flags.StringSliceVarP(&execCommand.Env, "env", "e", []string{}, "Set environment variables") + flags.StringArrayVarP(&execCommand.Env, "env", "e", []string{}, "Set environment variables") flags.BoolVarP(&execCommand.Interfactive, "interactive", "i", false, "Not supported. All exec commands are interactive by default") flags.BoolVarP(&execCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of") flags.BoolVar(&execCommand.Privileged, "privileged", false, "Give the process extended Linux capabilities inside the container. The default is false") flags.BoolVarP(&execCommand.Tty, "tty", "t", false, "Allocate a pseudo-TTY. The default is false") flags.StringVarP(&execCommand.User, "user", "u", "", "Sets the username or UID used and optionally the groupname or GID for the specified command") + flags.IntVar(&execCommand.PreserveFDs, "preserve-fds", 0, "Pass N additional file descriptors to the container") flags.StringVarP(&execCommand.Workdir, "workdir", "w", "", "Working directory inside the container") markFlagHiddenForRemoteClient("latest", flags) } @@ -82,22 +84,54 @@ func execCmd(c *cliconfig.ExecValues) error { return errors.Wrapf(err, "unable to exec into %s", args[0]) } - pid, err := ctr.PID() - if err != nil { - return err - } - became, ret, err := rootless.JoinNS(uint(pid)) - if err != nil { - return err + if c.PreserveFDs > 0 { + entries, err := ioutil.ReadDir("/proc/self/fd") + if err != nil { + return errors.Wrapf(err, "unable to read /proc/self/fd") + } + m := make(map[int]bool) + for _, e := range entries { + i, err := strconv.Atoi(e.Name()) + if err != nil { + if err != nil { + return errors.Wrapf(err, "cannot parse %s in /proc/self/fd", e.Name()) + } + } + m[i] = true + } + for i := 3; i < 3+c.PreserveFDs; i++ { + if _, found := m[i]; !found { + return errors.New("invalid --preserve-fds=N specified. Not enough FDs available") + } + } + } - if became { - os.Exit(ret) + + if os.Geteuid() != 0 { + var became bool + var ret int + + data, err := ioutil.ReadFile(ctr.Config().ConmonPidFile) + if err != nil { + return errors.Wrapf(err, "cannot read conmon PID file %q", ctr.Config().ConmonPidFile) + } + conmonPid, err := strconv.Atoi(string(data)) + if err != nil { + return errors.Wrapf(err, "cannot parse PID %q", data) + } + became, ret, err = rootless.JoinDirectUserAndMountNS(uint(conmonPid)) + if err != nil { + return err + } + if became { + os.Exit(ret) + } } // ENVIRONMENT VARIABLES env := map[string]string{} - if err := readKVStrings(env, []string{}, c.Env); err != nil { + if err := parse.ReadKVStrings(env, []string{}, c.Env); err != nil { return errors.Wrapf(err, "unable to process environment variables") } envs := []string{} @@ -113,5 +147,5 @@ func execCmd(c *cliconfig.ExecValues) error { streams.AttachError = true streams.AttachInput = true - return ctr.Exec(c.Tty, c.Privileged, envs, cmd, c.User, c.Workdir, streams) + return ctr.Exec(c.Tty, c.Privileged, envs, cmd, c.User, c.Workdir, streams, c.PreserveFDs) } |