diff options
-rw-r--r-- | cmd/podman/commit.go | 5 | ||||
-rw-r--r-- | contrib/spec/podman.spec.in | 1 | ||||
-rw-r--r-- | libpod/container_commit.go | 36 | ||||
-rw-r--r-- | pkg/rootless/rootless_linux.c | 55 | ||||
-rw-r--r-- | test/e2e/commit_test.go | 25 |
5 files changed, 95 insertions, 27 deletions
diff --git a/cmd/podman/commit.go b/cmd/podman/commit.go index 5963f8686..8d79c1e28 100644 --- a/cmd/podman/commit.go +++ b/cmd/podman/commit.go @@ -42,7 +42,7 @@ func init() { commitCommand.SetHelpTemplate(HelpTemplate()) commitCommand.SetUsageTemplate(UsageTemplate()) flags := commitCommand.Flags() - flags.StringSliceVarP(&commitCommand.Change, "change", "c", []string{}, fmt.Sprintf("Apply the following possible instructions to the created image (default []): %s", strings.Join(libpod.ChangeCmds, " | "))) + flags.StringArrayVarP(&commitCommand.Change, "change", "c", []string{}, fmt.Sprintf("Apply the following possible instructions to the created image (default []): %s", strings.Join(libpod.ChangeCmds, " | "))) flags.StringVarP(&commitCommand.Format, "format", "f", "oci", "`Format` of the image manifest and metadata") flags.StringVarP(&commitCommand.Message, "message", "m", "", "Set commit message for imported image") flags.StringVarP(&commitCommand.Author, "author", "a", "", "Set the author for the image committed") @@ -83,6 +83,9 @@ func commitCmd(c *cliconfig.CommitValues) error { if c.Flag("change").Changed { for _, change := range c.Change { splitChange := strings.Split(strings.ToUpper(change), "=") + if len(splitChange) == 1 { + splitChange = strings.Split(strings.ToUpper(change), " ") + } if !util.StringInSlice(splitChange[0], libpod.ChangeCmds) { return errors.Errorf("invalid syntax for --change: %s", change) } diff --git a/contrib/spec/podman.spec.in b/contrib/spec/podman.spec.in index 396304f8d..4b9cbd4cf 100644 --- a/contrib/spec/podman.spec.in +++ b/contrib/spec/podman.spec.in @@ -66,6 +66,7 @@ BuildRequires: libselinux-devel BuildRequires: ostree-devel BuildRequires: pkgconfig BuildRequires: make +BuildRequires: systemd-devel Requires: runc Requires: skopeo-containers Requires: containernetworking-plugins >= 0.6.0-3 diff --git a/libpod/container_commit.go b/libpod/container_commit.go index 3cc4b2c92..ae04f67bb 100644 --- a/libpod/container_commit.go +++ b/libpod/container_commit.go @@ -125,23 +125,48 @@ func (c *Container) Commit(ctx context.Context, destImage string, options Contai // Workdir importBuilder.SetWorkDir(c.Spec().Process.Cwd) + genCmd := func(cmd string) []string { + trim := func(cmd []string) []string { + if len(cmd) == 0 { + return cmd + } + + retCmd := []string{} + for _, c := range cmd { + if len(c) >= 2 { + if c[0] == '"' && c[len(c)-1] == '"' { + retCmd = append(retCmd, c[1:len(c)-1]) + continue + } + } + retCmd = append(retCmd, c) + } + return retCmd + } + if strings.HasPrefix(cmd, "[") { + cmd = strings.TrimPrefix(cmd, "[") + cmd = strings.TrimSuffix(cmd, "]") + return trim(strings.Split(cmd, ",")) + } + return []string{"/bin/sh", "-c", cmd} + } // Process user changes for _, change := range options.Changes { - splitChange := strings.SplitN(change, " ", 2) + splitChange := strings.SplitN(change, "=", 2) if len(splitChange) != 2 { - splitChange = strings.SplitN(change, "=", 2) + splitChange = strings.SplitN(change, " ", 2) if len(splitChange) < 2 { return nil, errors.Errorf("invalid change %s format", change) } } - change := strings.Split(splitChange[1], " ") switch strings.ToUpper(splitChange[0]) { case "CMD": - importBuilder.SetCmd(change) + importBuilder.SetCmd(genCmd(splitChange[1])) case "ENTRYPOINT": - importBuilder.SetEntrypoint(change) + importBuilder.SetEntrypoint(genCmd(splitChange[1])) case "ENV": + change := strings.Split(splitChange[1], " ") name := change[0] val := "" if len(change) < 2 { @@ -168,6 +193,7 @@ func (c *Container) Commit(ctx context.Context, destImage string, options Contai } importBuilder.SetPort(splitChange[1]) case "LABEL": + change := strings.Split(splitChange[1], " ") if len(change) < 2 { change = strings.Split(change[0], "=") } diff --git a/pkg/rootless/rootless_linux.c b/pkg/rootless/rootless_linux.c index 9cb79ed4d..1d32b1adb 100644 --- a/pkg/rootless/rootless_linux.c +++ b/pkg/rootless/rootless_linux.c @@ -16,11 +16,13 @@ #include <sys/types.h> #include <sys/prctl.h> #include <dirent.h> +#include <sys/select.h> static const char *_max_user_namespaces = "/proc/sys/user/max_user_namespaces"; static const char *_unprivileged_user_namespaces = "/proc/sys/kernel/unprivileged_userns_clone"; -static int n_files; +static int open_files_max_fd; +fd_set open_files_set; static void __attribute__((constructor)) init() { @@ -32,11 +34,16 @@ static void __attribute__((constructor)) init() { struct dirent *ent; + FD_ZERO (&open_files_set); for (ent = readdir (d); ent; ent = readdir (d)) { int fd = atoi (ent->d_name); - if (fd > n_files && fd != dirfd (d)) - n_files = fd; + if (fd != dirfd (d)) + { + if (fd > open_files_max_fd) + open_files_max_fd = fd; + FD_SET (fd, &open_files_set); + } } closedir (d); } @@ -164,8 +171,11 @@ reexec_userns_join (int userns, int mountns) { /* We passed down these fds, close them. */ int f; - for (f = 3; f < n_files; f++) - close (f); + for (f = 3; f < open_files_max_fd; f++) + { + if (FD_ISSET (f, &open_files_set)) + close (f); + } return pid; } @@ -274,22 +284,25 @@ reexec_in_user_namespace (int ready) check_proc_sys_userns_file (_max_user_namespaces); check_proc_sys_userns_file (_unprivileged_user_namespaces); } - if (pid) { - if (do_socket_activation) { - long num_fds; - num_fds = strtol(listen_fds, NULL, 10); - if (num_fds != LONG_MIN && num_fds != LONG_MAX) { - long i; - for (i = 0; i < num_fds; i++) { - close(3+i); + if (pid) + { + if (do_socket_activation) + { + long num_fds; + num_fds = strtol (listen_fds, NULL, 10); + if (num_fds != LONG_MIN && num_fds != LONG_MAX) + { + long i; + for (i = 3; i < num_fds + 3; i++) + if (FD_ISSET (i, &open_files_set)) + close (i); + } + unsetenv ("LISTEN_PID"); + unsetenv ("LISTEN_FDS"); + unsetenv ("LISTEN_FDNAMES"); } - } - unsetenv("LISTEN_PID"); - unsetenv("LISTEN_FDS"); - unsetenv("LISTEN_FDNAMES"); + return pid; } - return pid; - } argv = get_cmd_line_args (ppid); if (argv == NULL) @@ -300,8 +313,8 @@ reexec_in_user_namespace (int ready) if (do_socket_activation) { char s[32]; - sprintf(s, "%d", getpid()); - setenv("LISTEN_PID", s, true); + sprintf (s, "%d", getpid()); + setenv ("LISTEN_PID", s, true); } setenv ("_CONTAINERS_USERNS_CONFIGURED", "init", 1); diff --git a/test/e2e/commit_test.go b/test/e2e/commit_test.go index 93e1ea7af..3ece4887e 100644 --- a/test/e2e/commit_test.go +++ b/test/e2e/commit_test.go @@ -117,6 +117,31 @@ var _ = Describe("Podman commit", func() { Expect(foundBlue).To(Equal(true)) }) + It("podman commit container with change CMD flag", func() { + test := podmanTest.Podman([]string{"run", "--name", "test1", "-d", ALPINE, "ls"}) + test.WaitWithDefaultTimeout() + Expect(test.ExitCode()).To(Equal(0)) + Expect(podmanTest.NumberOfContainers()).To(Equal(1)) + + session := podmanTest.Podman([]string{"commit", "--change", "CMD a b c", "test1", "foobar.com/test1-image:latest"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + session = podmanTest.Podman([]string{"inspect", "--format", "{{.Config.Cmd}}", "foobar.com/test1-image:latest"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.OutputToString()).To(ContainSubstring("sh -c a b c")) + + session = podmanTest.Podman([]string{"commit", "--change", "CMD=[\"a\",\"b\",\"c\"]", "test1", "foobar.com/test1-image:latest"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + session = podmanTest.Podman([]string{"inspect", "--format", "{{.Config.Cmd}}", "foobar.com/test1-image:latest"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.OutputToString()).To(Not(ContainSubstring("sh -c"))) + }) + It("podman commit container with pause flag", func() { _, ec, _ := podmanTest.RunLsContainer("test1") Expect(ec).To(Equal(0)) |