summaryrefslogtreecommitdiff
path: root/cmd/podman
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/podman')
-rw-r--r--cmd/podman/common/completion.go155
-rw-r--r--cmd/podman/common/create.go7
-rw-r--r--cmd/podman/common/default.go3
-rw-r--r--cmd/podman/containers/checkpoint.go2
-rw-r--r--cmd/podman/containers/cleanup.go2
-rw-r--r--cmd/podman/containers/create.go22
-rw-r--r--cmd/podman/containers/diff.go6
-rw-r--r--cmd/podman/containers/init.go2
-rw-r--r--cmd/podman/containers/kill.go4
-rw-r--r--cmd/podman/containers/mount.go2
-rw-r--r--cmd/podman/containers/port.go4
-rw-r--r--cmd/podman/containers/restart.go2
-rw-r--r--cmd/podman/containers/restore.go2
-rw-r--r--cmd/podman/containers/rm.go11
-rw-r--r--cmd/podman/containers/run.go12
-rw-r--r--cmd/podman/containers/stop.go4
-rw-r--r--cmd/podman/containers/unmount.go4
-rw-r--r--cmd/podman/diff.go3
-rw-r--r--cmd/podman/diff/diff.go4
-rw-r--r--cmd/podman/images/build.go45
-rw-r--r--cmd/podman/images/diff.go4
-rw-r--r--cmd/podman/images/mount.go15
-rw-r--r--cmd/podman/images/save.go2
-rw-r--r--cmd/podman/images/search.go3
-rw-r--r--cmd/podman/images/trust_set.go2
-rw-r--r--cmd/podman/machine/init.go9
-rw-r--r--cmd/podman/machine/ssh.go4
-rw-r--r--cmd/podman/networks/reload.go2
-rw-r--r--cmd/podman/parse/net.go17
-rw-r--r--cmd/podman/pods/create.go22
-rw-r--r--cmd/podman/pods/kill.go2
-rw-r--r--cmd/podman/pods/pause.go2
-rw-r--r--cmd/podman/pods/ps.go3
-rw-r--r--cmd/podman/pods/restart.go2
-rw-r--r--cmd/podman/pods/rm.go2
-rw-r--r--cmd/podman/pods/start.go2
-rw-r--r--cmd/podman/pods/stop.go2
-rw-r--r--cmd/podman/pods/unpause.go2
-rw-r--r--cmd/podman/root.go2
-rw-r--r--cmd/podman/system/unshare.go21
-rw-r--r--cmd/podman/utils/error.go32
-rw-r--r--cmd/podman/utils/signals_linux.go15
-rw-r--r--cmd/podman/utils/signals_windows.go15
-rw-r--r--cmd/podman/validate/args.go93
-rw-r--r--cmd/podman/volumes/create.go4
-rw-r--r--cmd/podman/volumes/export.go6
-rw-r--r--cmd/podman/volumes/import.go7
47 files changed, 336 insertions, 252 deletions
diff --git a/cmd/podman/common/completion.go b/cmd/podman/common/completion.go
index 099fc267e..5eef5f982 100644
--- a/cmd/podman/common/completion.go
+++ b/cmd/podman/common/completion.go
@@ -4,10 +4,13 @@ import (
"bufio"
"fmt"
"os"
+ "path"
"reflect"
"strconv"
"strings"
+ "unicode"
+ libimageDefine "github.com/containers/common/libimage/define"
"github.com/containers/common/libnetwork/types"
"github.com/containers/common/pkg/config"
"github.com/containers/image/v5/pkg/sysregistriesv2"
@@ -16,8 +19,10 @@ import (
"github.com/containers/podman/v4/libpod/events"
"github.com/containers/podman/v4/pkg/domain/entities"
"github.com/containers/podman/v4/pkg/rootless"
+ "github.com/containers/podman/v4/pkg/signal"
systemdDefine "github.com/containers/podman/v4/pkg/systemd/define"
"github.com/containers/podman/v4/pkg/util"
+ securejoin "github.com/cyphar/filepath-securejoin"
"github.com/spf13/cobra"
)
@@ -279,6 +284,61 @@ func getNetworks(cmd *cobra.Command, toComplete string, cType completeType) ([]s
return suggestions, cobra.ShellCompDirectiveNoFileComp
}
+func getPathCompletion(root string, toComplete string) []string {
+ if toComplete == "" {
+ toComplete = "/"
+ }
+ // Important: securejoin is required to make sure we never leave the root mount point
+ userpath, err := securejoin.SecureJoin(root, toComplete)
+ if err != nil {
+ cobra.CompErrorln(err.Error())
+ return nil
+ }
+ var base string
+ f, err := os.Open(userpath)
+ if err != nil {
+ // Do not use path.Dir() since this cleans the paths which
+ // then no longer matches the user input.
+ userpath, base = path.Split(userpath)
+ toComplete, _ = path.Split(toComplete)
+ f, err = os.Open(userpath)
+ if err != nil {
+ return nil
+ }
+ }
+ stat, err := f.Stat()
+ if err != nil {
+ cobra.CompErrorln(err.Error())
+ return nil
+ }
+ if !stat.IsDir() {
+ // nothing to complete since it is no dir
+ return nil
+ }
+ entries, err := f.ReadDir(-1)
+ if err != nil {
+ cobra.CompErrorln(err.Error())
+ return nil
+ }
+ completions := make([]string, 0, len(entries))
+ for _, e := range entries {
+ if strings.HasPrefix(e.Name(), base) {
+ completions = append(completions, simplePathJoinUnix(toComplete, e.Name()))
+ }
+ }
+ return completions
+}
+
+// simplePathJoinUnix joins to path components by adding a slash only if p1 doesn't end with one.
+// We cannot use path.Join() for the completions logic because this one always calls Clean() on
+// the path which changes it from the input.
+func simplePathJoinUnix(p1, p2 string) string {
+ if p1[len(p1)-1] == '/' {
+ return p1 + p2
+ }
+ return p1 + "/" + p2
+}
+
// validCurrentCmdLine validates the current cmd line
// It utilizes the Args function from the cmd struct
// In most cases the Args function validates the args length but it
@@ -496,6 +556,11 @@ func AutocompleteImages(cmd *cobra.Command, args []string, toComplete string) ([
return getImages(cmd, toComplete)
}
+// AutocompleteImageSearchFilters - Autocomplate `search --filter`.
+func AutocompleteImageSearchFilters(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ return libimageDefine.SearchFilters, cobra.ShellCompDirectiveNoFileComp
+}
+
// AutocompletePodExitPolicy - Autocomplete pod exit policy.
func AutocompletePodExitPolicy(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return config.PodExitPolicies, cobra.ShellCompDirectiveNoFileComp
@@ -515,8 +580,32 @@ func AutocompleteCreateRun(cmd *cobra.Command, args []string, toComplete string)
}
return getImages(cmd, toComplete)
}
- // TODO: add path completion for files in the image
- return nil, cobra.ShellCompDirectiveDefault
+ // Mount the image and provide path completion
+ engine, err := setupImageEngine(cmd)
+ if err != nil {
+ cobra.CompErrorln(err.Error())
+ return nil, cobra.ShellCompDirectiveDefault
+ }
+
+ resp, err := engine.Mount(registry.Context(), []string{args[0]}, entities.ImageMountOptions{})
+ if err != nil {
+ cobra.CompErrorln(err.Error())
+ return nil, cobra.ShellCompDirectiveDefault
+ }
+ defer func() {
+ _, err := engine.Unmount(registry.Context(), []string{args[0]}, entities.ImageUnmountOptions{})
+ if err != nil {
+ cobra.CompErrorln(err.Error())
+ }
+ }()
+ if len(resp) != 1 {
+ return nil, cobra.ShellCompDirectiveDefault
+ }
+
+ // So this uses ShellCompDirectiveDefault to also still provide normal shell
+ // completion in case no path matches. This is useful if someone tries to get
+ // completion for paths that are not available in the image, e.g. /proc/...
+ return getPathCompletion(resp[0].Path, toComplete), cobra.ShellCompDirectiveDefault | cobra.ShellCompDirectiveNoSpace
}
// AutocompleteRegistries - Autocomplete registries.
@@ -564,14 +653,39 @@ func AutocompleteCpCommand(cmd *cobra.Command, args []string, toComplete string)
return nil, cobra.ShellCompDirectiveNoFileComp
}
if len(args) < 2 {
+ if i := strings.IndexByte(toComplete, ':'); i > -1 {
+ // Looks like the user already set the container.
+ // Lets mount it and provide path completion for files in the container.
+ engine, err := setupContainerEngine(cmd)
+ if err != nil {
+ cobra.CompErrorln(err.Error())
+ return nil, cobra.ShellCompDirectiveDefault
+ }
+
+ resp, err := engine.ContainerMount(registry.Context(), []string{toComplete[:i]}, entities.ContainerMountOptions{})
+ if err != nil {
+ cobra.CompErrorln(err.Error())
+ return nil, cobra.ShellCompDirectiveDefault
+ }
+ defer func() {
+ _, err := engine.ContainerUnmount(registry.Context(), []string{toComplete[:i]}, entities.ContainerUnmountOptions{})
+ if err != nil {
+ cobra.CompErrorln(err.Error())
+ }
+ }()
+ if len(resp) != 1 {
+ return nil, cobra.ShellCompDirectiveDefault
+ }
+ return prefixSlice(toComplete[:i+1], getPathCompletion(resp[0].Path, toComplete[i+1:])), cobra.ShellCompDirectiveDefault | cobra.ShellCompDirectiveNoSpace
+ }
+ // Suggest containers when they match the input otherwise normal shell completion is used
containers, _ := getContainers(cmd, toComplete, completeDefault)
for _, container := range containers {
- // TODO: Add path completion for inside the container if possible
if strings.HasPrefix(container, toComplete) {
- return containers, cobra.ShellCompDirectiveNoSpace
+ return suffixCompSlice(":", containers), cobra.ShellCompDirectiveNoSpace
}
}
- // else complete paths
+ // else complete paths on the host
return nil, cobra.ShellCompDirectiveDefault
}
// don't complete more than 2 args
@@ -595,7 +709,9 @@ func AutocompleteRunlabelCommand(cmd *cobra.Command, args []string, toComplete s
return nil, cobra.ShellCompDirectiveNoFileComp
}
if len(args) == 0 {
- // FIXME: What labels can we recommend here?
+ // This is unfortunate because the argument order is label followed by image.
+ // If it would be the other way around we could inspect the first arg and get
+ // all labels from it to suggest them.
return nil, cobra.ShellCompDirectiveNoFileComp
}
if len(args) == 1 {
@@ -800,8 +916,7 @@ func AutocompleteLogDriver(cmd *cobra.Command, args []string, toComplete string)
// AutocompleteLogOpt - Autocomplete log-opt options.
// -> "path=", "tag="
func AutocompleteLogOpt(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
- // FIXME: are these the only one? the man page states these but in the current shell completion they are more options
- logOptions := []string{"path=", "tag="}
+ logOptions := []string{"path=", "tag=", "max-size="}
if strings.HasPrefix(toComplete, "path=") {
return nil, cobra.ShellCompDirectiveDefault
}
@@ -840,10 +955,26 @@ func AutocompleteSecurityOption(cmd *cobra.Command, args []string, toComplete st
}
// AutocompleteStopSignal - Autocomplete stop signal options.
-// -> "SIGHUP", "SIGINT", "SIGKILL", "SIGTERM"
+// Autocompletes signals both lower or uppercase depending on the user input.
func AutocompleteStopSignal(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
- // FIXME: add more/different signals?
- stopSignals := []string{"SIGHUP", "SIGINT", "SIGKILL", "SIGTERM"}
+ // convertCase will convert a string to lowercase only if the user input is lowercase
+ convertCase := func(s string) string { return s }
+ if len(toComplete) > 0 && unicode.IsLower(rune(toComplete[0])) {
+ convertCase = strings.ToLower
+ }
+
+ prefix := ""
+ // if input starts with "SI" we have to add SIG in front
+ // since the signal map does not have this prefix but the option
+ // allows signals with and without SIG prefix
+ if strings.HasPrefix(toComplete, convertCase("SI")) {
+ prefix = "SIG"
+ }
+
+ stopSignals := make([]string, 0, len(signal.SignalMap))
+ for sig := range signal.SignalMap {
+ stopSignals = append(stopSignals, convertCase(prefix+sig))
+ }
return stopSignals, cobra.ShellCompDirectiveNoFileComp
}
@@ -1146,7 +1277,7 @@ func getMethodNames(f reflect.Value, prefix string) []formatSuggestion {
if kind == reflect.Struct || kind == reflect.Map {
suffix = "."
}
- // From a template users POV it is not importent when the use a struct field or method.
+ // From a template users POV it is not important when the use a struct field or method.
// They only notice the difference when the function requires arguments.
// So lets be nice and let the user know that this method requires arguments via the help text.
// Note since this is actually a method on a type the first argument is always fix so we should skip it.
diff --git a/cmd/podman/common/create.go b/cmd/podman/common/create.go
index d28becc8a..f89035be3 100644
--- a/cmd/podman/common/create.go
+++ b/cmd/podman/common/create.go
@@ -12,7 +12,7 @@ import (
"github.com/spf13/cobra"
)
-const sizeWithUnitFormat = "(format: `<number>[<unit>]`, where unit = b (bytes), k (kilobytes), m (megabytes), or g (gigabytes))"
+const sizeWithUnitFormat = "(format: `<number>[<unit>]`, where unit = b (bytes), k (kibibytes), m (mebibytes), or g (gibibytes))"
var containerConfig = registry.PodmanConfig()
@@ -255,9 +255,8 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions,
_ = cmd.RegisterFlagCompletionFunc(hostUserFlagName, completion.AutocompleteNone)
imageVolumeFlagName := "image-volume"
- createFlags.StringVar(
- &cf.ImageVolume,
- imageVolumeFlagName, DefaultImageVolume,
+ createFlags.String(
+ imageVolumeFlagName, containerConfig.Engine.ImageVolumeMode,
`Tells podman how to handle the builtin image volumes ("bind"|"tmpfs"|"ignore")`,
)
_ = cmd.RegisterFlagCompletionFunc(imageVolumeFlagName, AutocompleteImageVolume)
diff --git a/cmd/podman/common/default.go b/cmd/podman/common/default.go
index 7caec50ff..6f78d3d29 100644
--- a/cmd/podman/common/default.go
+++ b/cmd/podman/common/default.go
@@ -5,9 +5,6 @@ import (
)
var (
-
- // DefaultImageVolume default value
- DefaultImageVolume = "bind"
// Pull in configured json library
json = registry.JSONLibrary()
)
diff --git a/cmd/podman/containers/checkpoint.go b/cmd/podman/containers/checkpoint.go
index 40d689c4d..e0891f7a1 100644
--- a/cmd/podman/containers/checkpoint.go
+++ b/cmd/podman/containers/checkpoint.go
@@ -31,7 +31,7 @@ var (
Long: checkpointDescription,
RunE: checkpoint,
Args: func(cmd *cobra.Command, args []string) error {
- return validate.CheckAllLatestAndCIDFile(cmd, args, false, false)
+ return validate.CheckAllLatestAndIDFile(cmd, args, false, "")
},
ValidArgsFunction: common.AutocompleteContainersRunning,
Example: `podman container checkpoint --keep ctrID
diff --git a/cmd/podman/containers/cleanup.go b/cmd/podman/containers/cleanup.go
index aa2734607..a63e413fe 100644
--- a/cmd/podman/containers/cleanup.go
+++ b/cmd/podman/containers/cleanup.go
@@ -27,7 +27,7 @@ var (
Long: cleanupDescription,
RunE: cleanup,
Args: func(cmd *cobra.Command, args []string) error {
- return validate.CheckAllLatestAndCIDFile(cmd, args, false, false)
+ return validate.CheckAllLatestAndIDFile(cmd, args, false, "")
},
ValidArgsFunction: common.AutocompleteContainersExited,
Example: `podman container cleanup --latest
diff --git a/cmd/podman/containers/create.go b/cmd/podman/containers/create.go
index 29e138e30..0a513c606 100644
--- a/cmd/podman/containers/create.go
+++ b/cmd/podman/containers/create.go
@@ -9,6 +9,7 @@ import (
"github.com/containers/common/pkg/completion"
"github.com/containers/common/pkg/config"
+ cutil "github.com/containers/common/pkg/util"
"github.com/containers/image/v5/transports/alltransports"
"github.com/containers/image/v5/types"
"github.com/containers/podman/v4/cmd/podman/common"
@@ -101,28 +102,37 @@ func init() {
createFlags(containerCreateCommand)
}
-func create(cmd *cobra.Command, args []string) error {
- var (
- err error
- )
+func commonFlags(cmd *cobra.Command) error {
+ var err error
flags := cmd.Flags()
cliVals.Net, err = common.NetFlagsToNetOptions(nil, *flags)
if err != nil {
return err
}
+ if cmd.Flags().Changed("image-volume") {
+ cliVals.ImageVolume = cmd.Flag("image-volume").Value.String()
+ }
+ return nil
+}
+
+func create(cmd *cobra.Command, args []string) error {
+ if err := commonFlags(cmd); err != nil {
+ return err
+ }
+
// Check if initctr is used with --pod and the value is correct
if initctr := InitContainerType; cmd.Flags().Changed("init-ctr") {
if !cmd.Flags().Changed("pod") {
return errors.New("must specify pod value with init-ctr")
}
- if !util.StringInSlice(initctr, []string{define.AlwaysInitContainer, define.OneShotInitContainer}) {
+ if !cutil.StringInSlice(initctr, []string{define.AlwaysInitContainer, define.OneShotInitContainer}) {
return errors.Errorf("init-ctr value must be '%s' or '%s'", define.AlwaysInitContainer, define.OneShotInitContainer)
}
cliVals.InitContainerType = initctr
}
- cliVals, err = CreateInit(cmd, cliVals, false)
+ cliVals, err := CreateInit(cmd, cliVals, false)
if err != nil {
return err
}
diff --git a/cmd/podman/containers/diff.go b/cmd/podman/containers/diff.go
index e1a8ea729..15d3a3eff 100644
--- a/cmd/podman/containers/diff.go
+++ b/cmd/podman/containers/diff.go
@@ -32,13 +32,9 @@ func init() {
Parent: containerCmd,
})
- diffOpts = &entities.DiffOptions{}
+ diffOpts = new(entities.DiffOptions)
flags := diffCmd.Flags()
- // FIXME: Why does this exists? It is not used anywhere.
- flags.BoolVar(&diffOpts.Archive, "archive", true, "Save the diff as a tar archive")
- _ = flags.MarkHidden("archive")
-
formatFlagName := "format"
flags.StringVar(&diffOpts.Format, formatFlagName, "", "Change the output format (json)")
_ = diffCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteFormat(nil))
diff --git a/cmd/podman/containers/init.go b/cmd/podman/containers/init.go
index 7336a2332..649cdf1c9 100644
--- a/cmd/podman/containers/init.go
+++ b/cmd/podman/containers/init.go
@@ -21,7 +21,7 @@ var (
Long: initDescription,
RunE: initContainer,
Args: func(cmd *cobra.Command, args []string) error {
- return validate.CheckAllLatestAndCIDFile(cmd, args, false, false)
+ return validate.CheckAllLatestAndIDFile(cmd, args, false, "")
},
ValidArgsFunction: common.AutocompleteContainersCreated,
Example: `podman init --latest
diff --git a/cmd/podman/containers/kill.go b/cmd/podman/containers/kill.go
index e994fbf2c..eddefd196 100644
--- a/cmd/podman/containers/kill.go
+++ b/cmd/podman/containers/kill.go
@@ -25,7 +25,7 @@ var (
Long: killDescription,
RunE: kill,
Args: func(cmd *cobra.Command, args []string) error {
- return validate.CheckAllLatestAndCIDFile(cmd, args, false, true)
+ return validate.CheckAllLatestAndIDFile(cmd, args, false, "cidfile")
},
ValidArgsFunction: common.AutocompleteContainersRunning,
Example: `podman kill mywebserver
@@ -35,7 +35,7 @@ var (
containerKillCommand = &cobra.Command{
Args: func(cmd *cobra.Command, args []string) error {
- return validate.CheckAllLatestAndCIDFile(cmd, args, false, true)
+ return validate.CheckAllLatestAndIDFile(cmd, args, false, "cidfile")
},
Use: killCommand.Use,
Short: killCommand.Short,
diff --git a/cmd/podman/containers/mount.go b/cmd/podman/containers/mount.go
index 18177e3ce..16eb5d452 100644
--- a/cmd/podman/containers/mount.go
+++ b/cmd/podman/containers/mount.go
@@ -33,7 +33,7 @@ var (
Long: mountDescription,
RunE: mount,
Args: func(cmd *cobra.Command, args []string) error {
- return validate.CheckAllLatestAndCIDFile(cmd, args, true, false)
+ return validate.CheckAllLatestAndIDFile(cmd, args, true, "")
},
ValidArgsFunction: common.AutocompleteContainers,
}
diff --git a/cmd/podman/containers/port.go b/cmd/podman/containers/port.go
index 22d1d16d3..f10bdd5b4 100644
--- a/cmd/podman/containers/port.go
+++ b/cmd/podman/containers/port.go
@@ -23,7 +23,7 @@ var (
Long: portDescription,
RunE: port,
Args: func(cmd *cobra.Command, args []string) error {
- return validate.CheckAllLatestAndCIDFile(cmd, args, true, false)
+ return validate.CheckAllLatestAndIDFile(cmd, args, true, "")
},
ValidArgsFunction: common.AutocompleteContainerOneArg,
Example: `podman port --all
@@ -37,7 +37,7 @@ var (
Long: portDescription,
RunE: portCommand.RunE,
Args: func(cmd *cobra.Command, args []string) error {
- return validate.CheckAllLatestAndCIDFile(cmd, args, true, false)
+ return validate.CheckAllLatestAndIDFile(cmd, args, true, "")
},
ValidArgsFunction: portCommand.ValidArgsFunction,
Example: `podman container port --all
diff --git a/cmd/podman/containers/restart.go b/cmd/podman/containers/restart.go
index 69d8d71ea..25bbb61e3 100644
--- a/cmd/podman/containers/restart.go
+++ b/cmd/podman/containers/restart.go
@@ -26,7 +26,7 @@ var (
Long: restartDescription,
RunE: restart,
Args: func(cmd *cobra.Command, args []string) error {
- return validate.CheckAllLatestAndCIDFile(cmd, args, false, false)
+ return validate.CheckAllLatestAndIDFile(cmd, args, false, "")
},
ValidArgsFunction: common.AutocompleteContainers,
Example: `podman restart ctrID
diff --git a/cmd/podman/containers/restore.go b/cmd/podman/containers/restore.go
index eeda5a05f..1e4745354 100644
--- a/cmd/podman/containers/restore.go
+++ b/cmd/podman/containers/restore.go
@@ -28,7 +28,7 @@ var (
Long: restoreDescription,
RunE: restore,
Args: func(cmd *cobra.Command, args []string) error {
- return validate.CheckAllLatestAndCIDFile(cmd, args, true, false)
+ return validate.CheckAllLatestAndIDFile(cmd, args, true, "")
},
ValidArgsFunction: common.AutocompleteContainersAndImages,
Example: `podman container restore ctrID
diff --git a/cmd/podman/containers/rm.go b/cmd/podman/containers/rm.go
index 420e3c38d..bcbe86947 100644
--- a/cmd/podman/containers/rm.go
+++ b/cmd/podman/containers/rm.go
@@ -28,7 +28,7 @@ var (
Long: rmDescription,
RunE: rm,
Args: func(cmd *cobra.Command, args []string) error {
- return validate.CheckAllLatestAndCIDFile(cmd, args, false, true)
+ return validate.CheckAllLatestAndIDFile(cmd, args, false, "cidfile")
},
ValidArgsFunction: common.AutocompleteContainers,
Example: `podman rm imageID
@@ -123,9 +123,7 @@ func rm(cmd *cobra.Command, args []string) error {
// removeContainers will set the exit code according to the `podman-rm` man
// page.
func removeContainers(namesOrIDs []string, rmOptions entities.RmOptions, setExit bool) error {
- var (
- errs utils.OutputErrors
- )
+ var errs utils.OutputErrors
responses, err := registry.ContainerEngine().ContainerRm(context.Background(), namesOrIDs, rmOptions)
if err != nil {
if setExit {
@@ -135,8 +133,9 @@ func removeContainers(namesOrIDs []string, rmOptions entities.RmOptions, setExit
}
for _, r := range responses {
if r.Err != nil {
- // TODO this will not work with the remote client
- if errors.Cause(err) == define.ErrWillDeadlock {
+ // When using the API, errors.Cause(err) will never equal constant define.ErrWillDeadLock
+ if errors.Cause(r.Err) == define.ErrWillDeadlock ||
+ errors.Cause(r.Err).Error() == define.ErrWillDeadlock.Error() {
logrus.Errorf("Potential deadlock detected - please run 'podman system renumber' to resolve")
}
if setExit {
diff --git a/cmd/podman/containers/run.go b/cmd/podman/containers/run.go
index 951981293..a6c500afa 100644
--- a/cmd/podman/containers/run.go
+++ b/cmd/podman/containers/run.go
@@ -109,7 +109,9 @@ func init() {
}
func run(cmd *cobra.Command, args []string) error {
- var err error
+ if err := commonFlags(cmd); err != nil {
+ return err
+ }
// TODO: Breaking change should be made fatal in next major Release
if cliVals.TTY && cliVals.Interactive && !term.IsTerminal(int(os.Stdin.Fd())) {
@@ -122,14 +124,10 @@ func run(cmd *cobra.Command, args []string) error {
}
}
- flags := cmd.Flags()
- cliVals.Net, err = common.NetFlagsToNetOptions(nil, *flags)
- if err != nil {
- return err
- }
runOpts.CIDFile = cliVals.CIDFile
runOpts.Rm = cliVals.Rm
- if cliVals, err = CreateInit(cmd, cliVals, false); err != nil {
+ cliVals, err := CreateInit(cmd, cliVals, false)
+ if err != nil {
return err
}
diff --git a/cmd/podman/containers/stop.go b/cmd/podman/containers/stop.go
index af2250abb..def608fea 100644
--- a/cmd/podman/containers/stop.go
+++ b/cmd/podman/containers/stop.go
@@ -26,7 +26,7 @@ var (
Long: stopDescription,
RunE: stop,
Args: func(cmd *cobra.Command, args []string) error {
- return validate.CheckAllLatestAndCIDFile(cmd, args, false, true)
+ return validate.CheckAllLatestAndIDFile(cmd, args, false, "cidfile")
},
ValidArgsFunction: common.AutocompleteContainersRunning,
Example: `podman stop ctrID
@@ -40,7 +40,7 @@ var (
Long: stopCommand.Long,
RunE: stopCommand.RunE,
Args: func(cmd *cobra.Command, args []string) error {
- return validate.CheckAllLatestAndCIDFile(cmd, args, false, true)
+ return validate.CheckAllLatestAndIDFile(cmd, args, false, "cidfile")
},
ValidArgsFunction: stopCommand.ValidArgsFunction,
Example: `podman container stop ctrID
diff --git a/cmd/podman/containers/unmount.go b/cmd/podman/containers/unmount.go
index 26b8cfcc5..6869de2e2 100644
--- a/cmd/podman/containers/unmount.go
+++ b/cmd/podman/containers/unmount.go
@@ -27,7 +27,7 @@ var (
Long: description,
RunE: unmount,
Args: func(cmd *cobra.Command, args []string) error {
- return validate.CheckAllLatestAndCIDFile(cmd, args, false, false)
+ return validate.CheckAllLatestAndIDFile(cmd, args, false, "")
},
ValidArgsFunction: common.AutocompleteContainers,
Example: `podman unmount ctrID
@@ -43,7 +43,7 @@ var (
Long: unmountCommand.Long,
RunE: unmountCommand.RunE,
Args: func(cmd *cobra.Command, args []string) error {
- return validate.CheckAllLatestAndCIDFile(cmd, args, false, false)
+ return validate.CheckAllLatestAndIDFile(cmd, args, false, "")
},
ValidArgsFunction: common.AutocompleteContainers,
Example: `podman container unmount ctrID
diff --git a/cmd/podman/diff.go b/cmd/podman/diff.go
index 7b78c8312..ec98fb5b5 100644
--- a/cmd/podman/diff.go
+++ b/cmd/podman/diff.go
@@ -35,9 +35,6 @@ func init() {
Command: diffCmd,
})
flags := diffCmd.Flags()
- // FIXME: Why does this exists? It is not used anywhere.
- flags.BoolVar(&diffOpts.Archive, "archive", true, "Save the diff as a tar archive")
- _ = flags.MarkHidden("archive")
formatFlagName := "format"
flags.StringVar(&diffOpts.Format, formatFlagName, "", "Change the output format (json)")
diff --git a/cmd/podman/diff/diff.go b/cmd/podman/diff/diff.go
index a26502de9..15c55852a 100644
--- a/cmd/podman/diff/diff.go
+++ b/cmd/podman/diff/diff.go
@@ -13,7 +13,7 @@ import (
"github.com/spf13/cobra"
)
-func Diff(cmd *cobra.Command, args []string, options entities.DiffOptions) error {
+func Diff(_ *cobra.Command, args []string, options entities.DiffOptions) error {
results, err := registry.ContainerEngine().Diff(registry.GetContext(), args, options)
if err != nil {
return err
@@ -63,7 +63,7 @@ func changesToTable(diffs *entities.DiffReport) error {
return nil
}
-// IDOrLatestArgs used to validate a nameOrId was provided or the "--latest" flag
+// ValidateContainerDiffArgs used to validate a nameOrId was provided or the "--latest" flag
func ValidateContainerDiffArgs(cmd *cobra.Command, args []string) error {
given, _ := cmd.Flags().GetBool("latest")
if len(args) > 0 && !given {
diff --git a/cmd/podman/images/build.go b/cmd/podman/images/build.go
index 3ea60e18a..940ea6e42 100644
--- a/cmd/podman/images/build.go
+++ b/cmd/podman/images/build.go
@@ -197,9 +197,8 @@ func buildFlags(cmd *cobra.Command) {
// build executes the build command.
func build(cmd *cobra.Command, args []string) error {
if (cmd.Flags().Changed("squash") && cmd.Flags().Changed("layers")) ||
- (cmd.Flags().Changed("squash-all") && cmd.Flags().Changed("layers")) ||
(cmd.Flags().Changed("squash-all") && cmd.Flags().Changed("squash")) {
- return errors.New("cannot specify --squash, --squash-all and --layers options together")
+ return errors.New("cannot specify --squash with --layers and --squash-all with --squash")
}
if cmd.Flag("output").Changed && registry.IsRemote() {
@@ -418,7 +417,13 @@ func buildFlagsWrapperToOptions(c *cobra.Command, contextDir string, flags *buil
// Squash-all invoked, squash both new and old layers into one.
if c.Flags().Changed("squash-all") {
flags.Squash = true
- flags.Layers = false
+ if !c.Flags().Changed("layers") {
+ // Buildah supports using layers and --squash together
+ // after https://github.com/containers/buildah/pull/3674
+ // so podman must honor if user wants to still use layers
+ // with --squash-all.
+ flags.Layers = false
+ }
}
var stdin io.Reader
@@ -442,22 +447,6 @@ func buildFlagsWrapperToOptions(c *cobra.Command, contextDir string, flags *buil
return nil, err
}
- // `buildah bud --layers=false` acts like `docker build --squash` does.
- // That is all of the new layers created during the build process are
- // condensed into one, any layers present prior to this build are retained
- // without condensing. `buildah bud --squash` squashes both new and old
- // layers down into one. Translate Podman commands into Buildah.
- // Squash invoked, retain old layers, squash new layers into one.
- if c.Flags().Changed("squash") && flags.Squash {
- flags.Squash = false
- flags.Layers = false
- }
- // Squash-all invoked, squash both new and old layers into one.
- if c.Flags().Changed("squash-all") {
- flags.Squash = true
- flags.Layers = false
- }
-
compression := buildahDefine.Gzip
if flags.DisableCompression {
compression = buildahDefine.Uncompressed
@@ -513,9 +502,26 @@ func buildFlagsWrapperToOptions(c *cobra.Command, contextDir string, flags *buil
return nil, errors.Wrapf(err, "unable to obtain decrypt config")
}
+ additionalBuildContext := make(map[string]*buildahDefine.AdditionalBuildContext)
+ if c.Flag("build-context").Changed {
+ for _, contextString := range flags.BuildContext {
+ av := strings.SplitN(contextString, "=", 2)
+ if len(av) > 1 {
+ parseAdditionalBuildContext, err := parse.GetAdditionalBuildContext(av[1])
+ if err != nil {
+ return nil, errors.Wrapf(err, "while parsing additional build context")
+ }
+ additionalBuildContext[av[0]] = &parseAdditionalBuildContext
+ } else {
+ return nil, fmt.Errorf("while parsing additional build context: %q, accepts value in the form of key=value", av)
+ }
+ }
+ }
+
opts := buildahDefine.BuildOptions{
AddCapabilities: flags.CapAdd,
AdditionalTags: tags,
+ AdditionalBuildContexts: additionalBuildContext,
AllPlatforms: flags.AllPlatforms,
Annotations: flags.Annotation,
Args: args,
@@ -525,6 +531,7 @@ func buildFlagsWrapperToOptions(c *cobra.Command, contextDir string, flags *buil
Compression: compression,
ConfigureNetwork: networkPolicy,
ContextDirectory: contextDir,
+ CPPFlags: flags.CPPFlags,
DefaultMountsFilePath: containerConfig.Containers.DefaultMountsFile,
Devices: flags.Devices,
DropCapabilities: flags.CapDrop,
diff --git a/cmd/podman/images/diff.go b/cmd/podman/images/diff.go
index 13a8f1d9d..a017d569d 100644
--- a/cmd/podman/images/diff.go
+++ b/cmd/podman/images/diff.go
@@ -34,9 +34,7 @@ func init() {
}
func diffFlags(flags *pflag.FlagSet) {
- diffOpts = &entities.DiffOptions{}
- flags.BoolVar(&diffOpts.Archive, "archive", true, "Save the diff as a tar archive")
- _ = flags.MarkDeprecated("archive", "Provided for backwards compatibility, has no impact on output.")
+ diffOpts = new(entities.DiffOptions)
formatFlagName := "format"
flags.StringVar(&diffOpts.Format, formatFlagName, "", "Change the output format (json)")
diff --git a/cmd/podman/images/mount.go b/cmd/podman/images/mount.go
index d5ab3d274..532d96196 100644
--- a/cmd/podman/images/mount.go
+++ b/cmd/podman/images/mount.go
@@ -7,7 +7,6 @@ import (
"github.com/containers/common/pkg/report"
"github.com/containers/podman/v4/cmd/podman/common"
"github.com/containers/podman/v4/cmd/podman/registry"
- "github.com/containers/podman/v4/cmd/podman/utils"
"github.com/containers/podman/v4/pkg/domain/entities"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@@ -71,16 +70,12 @@ func mount(cmd *cobra.Command, args []string) error {
return err
}
- if len(args) > 0 || mountOpts.All {
- var errs utils.OutputErrors
- for _, r := range reports {
- if r.Err == nil {
- fmt.Println(r.Path)
- continue
- }
- errs = append(errs, r.Err)
+ if len(args) == 1 && mountOpts.Format == "" && !mountOpts.All {
+ if len(reports) != 1 {
+ return fmt.Errorf("internal error: expected 1 report but got %d", len(reports))
}
- return errs.PrintErrors()
+ fmt.Println(reports[0].Path)
+ return nil
}
switch {
diff --git a/cmd/podman/images/save.go b/cmd/podman/images/save.go
index 3394c2e99..d85d688ee 100644
--- a/cmd/podman/images/save.go
+++ b/cmd/podman/images/save.go
@@ -6,12 +6,12 @@ import (
"strings"
"github.com/containers/common/pkg/completion"
+ "github.com/containers/common/pkg/util"
"github.com/containers/podman/v4/cmd/podman/common"
"github.com/containers/podman/v4/cmd/podman/parse"
"github.com/containers/podman/v4/cmd/podman/registry"
"github.com/containers/podman/v4/libpod/define"
"github.com/containers/podman/v4/pkg/domain/entities"
- "github.com/containers/podman/v4/pkg/util"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"golang.org/x/term"
diff --git a/cmd/podman/images/search.go b/cmd/podman/images/search.go
index 335ea2b5a..a18f7a11d 100644
--- a/cmd/podman/images/search.go
+++ b/cmd/podman/images/search.go
@@ -83,8 +83,7 @@ func searchFlags(cmd *cobra.Command) {
filterFlagName := "filter"
flags.StringSliceVarP(&searchOptions.Filters, filterFlagName, "f", []string{}, "Filter output based on conditions provided (default [])")
- // TODO add custom filter function
- _ = cmd.RegisterFlagCompletionFunc(filterFlagName, completion.AutocompleteNone)
+ _ = cmd.RegisterFlagCompletionFunc(filterFlagName, common.AutocompleteImageSearchFilters)
formatFlagName := "format"
flags.StringVar(&searchOptions.Format, formatFlagName, "", "Change the output format to JSON or a Go template")
diff --git a/cmd/podman/images/trust_set.go b/cmd/podman/images/trust_set.go
index fff035d12..f4ff0cffc 100644
--- a/cmd/podman/images/trust_set.go
+++ b/cmd/podman/images/trust_set.go
@@ -5,10 +5,10 @@ import (
"regexp"
"github.com/containers/common/pkg/completion"
+ "github.com/containers/common/pkg/util"
"github.com/containers/podman/v4/cmd/podman/common"
"github.com/containers/podman/v4/cmd/podman/registry"
"github.com/containers/podman/v4/pkg/domain/entities"
- "github.com/containers/podman/v4/pkg/util"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
diff --git a/cmd/podman/machine/init.go b/cmd/podman/machine/init.go
index 6c31f3531..612c36057 100644
--- a/cmd/podman/machine/init.go
+++ b/cmd/podman/machine/init.go
@@ -25,16 +25,14 @@ var (
Example: `podman machine init myvm`,
ValidArgsFunction: completion.AutocompleteNone,
}
-)
-var (
initOpts = machine.InitOptions{}
defaultMachineName = machine.DefaultMachineName
now bool
)
// maxMachineNameSize is set to thirty to limit huge machine names primarily
-// because macos has a much smaller file size limit.
+// because macOS has a much smaller file size limit.
const maxMachineNameSize = 30
func init() {
@@ -111,8 +109,7 @@ func init() {
flags.BoolVar(&initOpts.Rootful, rootfulFlagName, false, "Whether this machine should prefer rootful container execution")
}
-// TODO should we allow for a users to append to the qemu cmdline?
-func initMachine(cmd *cobra.Command, args []string) error {
+func initMachine(_ *cobra.Command, args []string) error {
var (
err error
vm machine.VM
@@ -122,7 +119,7 @@ func initMachine(cmd *cobra.Command, args []string) error {
initOpts.Name = defaultMachineName
if len(args) > 0 {
if len(args[0]) > maxMachineNameSize {
- return errors.New("machine name must be 30 characters or less")
+ return errors.Errorf("machine name %q must be %d characters or less", args[0], maxMachineNameSize)
}
initOpts.Name = args[0]
}
diff --git a/cmd/podman/machine/ssh.go b/cmd/podman/machine/ssh.go
index 4a86da67a..8261f3607 100644
--- a/cmd/podman/machine/ssh.go
+++ b/cmd/podman/machine/ssh.go
@@ -9,6 +9,7 @@ import (
"github.com/containers/common/pkg/completion"
"github.com/containers/common/pkg/config"
"github.com/containers/podman/v4/cmd/podman/registry"
+ "github.com/containers/podman/v4/cmd/podman/utils"
"github.com/containers/podman/v4/pkg/machine"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@@ -89,7 +90,8 @@ func ssh(cmd *cobra.Command, args []string) error {
if err != nil {
return errors.Wrapf(err, "vm %s not found", vmName)
}
- return vm.SSH(vmName, sshOpts)
+ err = vm.SSH(vmName, sshOpts)
+ return utils.HandleOSExecError(err)
}
func remoteConnectionUsername() (string, error) {
diff --git a/cmd/podman/networks/reload.go b/cmd/podman/networks/reload.go
index 7b6323187..66248e9fb 100644
--- a/cmd/podman/networks/reload.go
+++ b/cmd/podman/networks/reload.go
@@ -21,7 +21,7 @@ var (
Long: networkReloadDescription,
RunE: networkReload,
Args: func(cmd *cobra.Command, args []string) error {
- return validate.CheckAllLatestAndCIDFile(cmd, args, false, false)
+ return validate.CheckAllLatestAndIDFile(cmd, args, false, "")
},
ValidArgsFunction: common.AutocompleteContainers,
Example: `podman network reload --latest
diff --git a/cmd/podman/parse/net.go b/cmd/podman/parse/net.go
index 870690db3..b616e1029 100644
--- a/cmd/podman/parse/net.go
+++ b/cmd/podman/parse/net.go
@@ -18,6 +18,8 @@ import (
const (
Protocol_TCP Protocol = 0
Protocol_UDP Protocol = 1
+ LabelType string = "label"
+ ENVType string = "env"
)
type Protocol int32
@@ -89,9 +91,7 @@ func GetAllLabels(labelFile, inputLabels []string) (map[string]string, error) {
// There's an argument that we SHOULD be doing that parsing for
// all environment variables, even those sourced from files, but
// that would require a substantial rework.
- if err := parseEnvFile(labels, file); err != nil {
- // FIXME: parseEnvFile is using parseEnv, so we need to add extra
- // logic for labels.
+ if err := parseEnvOrLabelFile(labels, file, LabelType); err != nil {
return nil, err
}
}
@@ -109,7 +109,7 @@ func GetAllLabels(labelFile, inputLabels []string) (map[string]string, error) {
return labels, nil
}
-func parseEnv(env map[string]string, line string) error {
+func parseEnvOrLabel(env map[string]string, line, configType string) error {
data := strings.SplitN(line, "=", 2)
// catch invalid variables such as "=" or "=A"
@@ -137,7 +137,7 @@ func parseEnv(env map[string]string, line string) error {
env[part[0]] = part[1]
}
}
- } else {
+ } else if configType == ENVType {
// if only a pass-through variable is given, clean it up.
if val, ok := os.LookupEnv(name); ok {
env[name] = val
@@ -147,8 +147,9 @@ func parseEnv(env map[string]string, line string) error {
return nil
}
-// parseEnvFile reads a file with environment variables enumerated by lines
-func parseEnvFile(env map[string]string, filename string) error {
+// parseEnvOrLabelFile reads a file with environment variables enumerated by lines
+// configType should be set to either "label" or "env" based on what type is being parsed
+func parseEnvOrLabelFile(envOrLabel map[string]string, filename, configType string) error {
fh, err := os.Open(filename)
if err != nil {
return err
@@ -161,7 +162,7 @@ func parseEnvFile(env map[string]string, filename string) error {
line := strings.TrimLeft(scanner.Text(), whiteSpaces)
// line is not empty, and not starting with '#'
if len(line) > 0 && !strings.HasPrefix(line, "#") {
- if err := parseEnv(env, line); err != nil {
+ if err := parseEnvOrLabel(envOrLabel, line, configType); err != nil {
return err
}
}
diff --git a/cmd/podman/pods/create.go b/cmd/podman/pods/create.go
index 62f820790..e2f80bdbc 100644
--- a/cmd/podman/pods/create.go
+++ b/cmd/podman/pods/create.go
@@ -16,7 +16,6 @@ import (
"github.com/containers/podman/v4/cmd/podman/containers"
"github.com/containers/podman/v4/cmd/podman/parse"
"github.com/containers/podman/v4/cmd/podman/registry"
- "github.com/containers/podman/v4/cmd/podman/validate"
"github.com/containers/podman/v4/libpod/define"
"github.com/containers/podman/v4/pkg/domain/entities"
"github.com/containers/podman/v4/pkg/errorhandling"
@@ -36,12 +35,14 @@ var (
You can then start it at any time with the podman pod start <pod_id> command. The pod will be created with the initial state 'created'.`
createCommand = &cobra.Command{
- Use: "create [options]",
- Args: validate.NoArgs,
+ Use: "create [options] [NAME]",
+ Args: cobra.MaximumNArgs(1),
Short: "Create a new empty pod",
Long: podCreateDescription,
RunE: create,
ValidArgsFunction: completion.AutocompleteNone,
+ Example: `podman pod create
+ podman pod create --label foo=bar mypod`,
}
)
@@ -115,6 +116,12 @@ func create(cmd *cobra.Command, args []string) error {
rawImageName string
podName string
)
+ if len(args) > 0 {
+ if len(createOptions.Name) > 0 {
+ return fmt.Errorf("cannot specify --name and NAME at the same time")
+ }
+ createOptions.Name = args[0]
+ }
labelFile = infraOptions.LabelFile
labels = infraOptions.Label
createOptions.Labels, err = parse.GetAllLabels(labelFile, labels)
@@ -128,7 +135,7 @@ func create(cmd *cobra.Command, args []string) error {
img := imageName
if !createOptions.Infra {
if cmd.Flag("no-hosts").Changed {
- return fmt.Errorf("cannot specify no-hosts without an infra container")
+ return fmt.Errorf("cannot specify --no-hosts without an infra container")
}
flags := cmd.Flags()
createOptions.Net, err = common.NetFlagsToNetOptions(nil, *flags)
@@ -159,7 +166,12 @@ func create(cmd *cobra.Command, args []string) error {
if strings.Contains(share, "cgroup") && shareParent {
return errors.Wrapf(define.ErrInvalidArg, "cannot define the pod as the cgroup parent at the same time as joining the infra container's cgroupNS")
}
- createOptions.Share = strings.Split(share, ",")
+
+ if strings.HasPrefix(share, "+") {
+ createOptions.Share = append(createOptions.Share, strings.Split(specgen.DefaultKernelNamespaces, ",")...)
+ share = share[1:]
+ }
+ createOptions.Share = append(createOptions.Share, strings.Split(share, ",")...)
createOptions.ShareParent = &shareParent
if cmd.Flag("infra-command").Changed {
// Only send content to server side if user changed defaults
diff --git a/cmd/podman/pods/kill.go b/cmd/podman/pods/kill.go
index 7216e08bb..5d3b15dc3 100644
--- a/cmd/podman/pods/kill.go
+++ b/cmd/podman/pods/kill.go
@@ -22,7 +22,7 @@ var (
Long: podKillDescription,
RunE: kill,
Args: func(cmd *cobra.Command, args []string) error {
- return validate.CheckAllLatestAndCIDFile(cmd, args, false, false)
+ return validate.CheckAllLatestAndIDFile(cmd, args, false, "")
},
ValidArgsFunction: common.AutocompletePodsRunning,
Example: `podman pod kill podID
diff --git a/cmd/podman/pods/pause.go b/cmd/podman/pods/pause.go
index adc54d171..389fb8415 100644
--- a/cmd/podman/pods/pause.go
+++ b/cmd/podman/pods/pause.go
@@ -22,7 +22,7 @@ var (
Long: podPauseDescription,
RunE: pause,
Args: func(cmd *cobra.Command, args []string) error {
- return validate.CheckAllLatestAndCIDFile(cmd, args, false, false)
+ return validate.CheckAllLatestAndIDFile(cmd, args, false, "")
},
ValidArgsFunction: common.AutocompletePodsRunning,
Example: `podman pod pause podID1 podID2
diff --git a/cmd/podman/pods/ps.go b/cmd/podman/pods/ps.go
index 1275e65dc..aa42e1983 100644
--- a/cmd/podman/pods/ps.go
+++ b/cmd/podman/pods/ps.go
@@ -24,7 +24,7 @@ var (
// Command: podman pod _ps_
psCmd = &cobra.Command{
- Use: "ps [options]",
+ Use: "ps [options]",
Aliases: []string{"ls", "list"},
Short: "List pods",
Long: psDescription,
@@ -49,7 +49,6 @@ func init() {
flags.BoolVar(&psInput.CtrNames, "ctr-names", false, "Display the container names")
flags.BoolVar(&psInput.CtrIds, "ctr-ids", false, "Display the container UUIDs. If no-trunc is not set they will be truncated")
flags.BoolVar(&psInput.CtrStatus, "ctr-status", false, "Display the container status")
- // TODO should we make this a [] ?
filterFlagName := "filter"
flags.StringSliceVarP(&inputFilters, filterFlagName, "f", []string{}, "Filter output based on conditions given")
diff --git a/cmd/podman/pods/restart.go b/cmd/podman/pods/restart.go
index 6d624806a..a8e31ce07 100644
--- a/cmd/podman/pods/restart.go
+++ b/cmd/podman/pods/restart.go
@@ -22,7 +22,7 @@ var (
Long: podRestartDescription,
RunE: restart,
Args: func(cmd *cobra.Command, args []string) error {
- return validate.CheckAllLatestAndCIDFile(cmd, args, false, false)
+ return validate.CheckAllLatestAndIDFile(cmd, args, false, "")
},
ValidArgsFunction: common.AutocompletePods,
Example: `podman pod restart podID1 podID2
diff --git a/cmd/podman/pods/rm.go b/cmd/podman/pods/rm.go
index 52a815534..16b7191c9 100644
--- a/cmd/podman/pods/rm.go
+++ b/cmd/podman/pods/rm.go
@@ -35,7 +35,7 @@ var (
Long: podRmDescription,
RunE: rm,
Args: func(cmd *cobra.Command, args []string) error {
- return validate.CheckAllLatestAndPodIDFile(cmd, args, false, true)
+ return validate.CheckAllLatestAndIDFile(cmd, args, false, "pod-id-file")
},
ValidArgsFunction: common.AutocompletePods,
Example: `podman pod rm mywebserverpod
diff --git a/cmd/podman/pods/start.go b/cmd/podman/pods/start.go
index b668cdd61..9436d34a5 100644
--- a/cmd/podman/pods/start.go
+++ b/cmd/podman/pods/start.go
@@ -31,7 +31,7 @@ var (
Long: podStartDescription,
RunE: start,
Args: func(cmd *cobra.Command, args []string) error {
- return validate.CheckAllLatestAndPodIDFile(cmd, args, false, true)
+ return validate.CheckAllLatestAndIDFile(cmd, args, false, "pod-id-file")
},
ValidArgsFunction: common.AutocompletePods,
Example: `podman pod start podID
diff --git a/cmd/podman/pods/stop.go b/cmd/podman/pods/stop.go
index c8c3d2732..e8f82bee9 100644
--- a/cmd/podman/pods/stop.go
+++ b/cmd/podman/pods/stop.go
@@ -36,7 +36,7 @@ var (
Long: podStopDescription,
RunE: stop,
Args: func(cmd *cobra.Command, args []string) error {
- return validate.CheckAllLatestAndPodIDFile(cmd, args, false, true)
+ return validate.CheckAllLatestAndIDFile(cmd, args, false, "pod-id-file")
},
ValidArgsFunction: common.AutocompletePodsRunning,
Example: `podman pod stop mywebserverpod
diff --git a/cmd/podman/pods/unpause.go b/cmd/podman/pods/unpause.go
index a308a82c3..8a0a24e98 100644
--- a/cmd/podman/pods/unpause.go
+++ b/cmd/podman/pods/unpause.go
@@ -22,7 +22,7 @@ var (
Long: podUnpauseDescription,
RunE: unpause,
Args: func(cmd *cobra.Command, args []string) error {
- return validate.CheckAllLatestAndCIDFile(cmd, args, false, false)
+ return validate.CheckAllLatestAndIDFile(cmd, args, false, "")
},
// TODO have a function which shows only pods which could be unpaused
// for now show all
diff --git a/cmd/podman/root.go b/cmd/podman/root.go
index 2bd4fa723..1892ff9f7 100644
--- a/cmd/podman/root.go
+++ b/cmd/podman/root.go
@@ -423,7 +423,7 @@ func rootFlags(cmd *cobra.Command, opts *entities.PodmanConfig) {
// -s is deprecated due to conflict with -s on subcommands
storageDriverFlagName := "storage-driver"
pFlags.StringVar(&opts.StorageDriver, storageDriverFlagName, "", "Select which storage driver is used to manage storage of images and containers")
- _ = cmd.RegisterFlagCompletionFunc(storageDriverFlagName, completion.AutocompleteNone) //TODO: what can we recommend here?
+ _ = cmd.RegisterFlagCompletionFunc(storageDriverFlagName, completion.AutocompleteNone)
tmpdirFlagName := "tmpdir"
pFlags.StringVar(&opts.Engine.TmpDir, tmpdirFlagName, "", "Path to the tmp directory for libpod state content.\n\nNote: use the environment variable 'TMPDIR' to change the temporary storage location for container images, '/var/tmp'.\n")
diff --git a/cmd/podman/system/unshare.go b/cmd/podman/system/unshare.go
index 0ae5b81ad..1ed08eac3 100644
--- a/cmd/podman/system/unshare.go
+++ b/cmd/podman/system/unshare.go
@@ -2,10 +2,10 @@ package system
import (
"os"
- "os/exec"
"github.com/containers/common/pkg/completion"
"github.com/containers/podman/v4/cmd/podman/registry"
+ "github.com/containers/podman/v4/cmd/podman/utils"
"github.com/containers/podman/v4/pkg/domain/entities"
"github.com/containers/podman/v4/pkg/rootless"
"github.com/pkg/errors"
@@ -60,22 +60,5 @@ func unshare(cmd *cobra.Command, args []string) error {
}
err := registry.ContainerEngine().Unshare(registry.Context(), args, unshareOptions)
- if err != nil {
- if exitError, ok := err.(*exec.ExitError); ok {
- // the user command inside the unshare env has failed
- // we set the exit code, do not return the error to the user
- // otherwise "exit status X" will be printed
- registry.SetExitCode(exitError.ExitCode())
- return nil
- }
- // cmd.Run() can return fs.ErrNotExist, fs.ErrPermission or exec.ErrNotFound
- // follow podman run/exec standard with the exit codes
- if errors.Is(err, os.ErrNotExist) || errors.Is(err, exec.ErrNotFound) {
- registry.SetExitCode(127)
- } else if errors.Is(err, os.ErrPermission) {
- registry.SetExitCode(126)
- }
- return err
- }
- return nil
+ return utils.HandleOSExecError(err)
}
diff --git a/cmd/podman/utils/error.go b/cmd/podman/utils/error.go
index 2aaa71373..3efff0301 100644
--- a/cmd/podman/utils/error.go
+++ b/cmd/podman/utils/error.go
@@ -4,10 +4,12 @@ import (
"errors"
"fmt"
"os"
+ "os/exec"
"strconv"
"strings"
buildahCLI "github.com/containers/buildah/pkg/cli"
+ "github.com/containers/podman/v4/cmd/podman/registry"
)
type OutputErrors []error
@@ -43,3 +45,33 @@ func ExitCodeFromBuildError(errorMsg string) (int, error) {
}
return buildahCLI.ExecErrorCodeGeneric, errors.New("message does not contains a valid exit code")
}
+
+// HandleOSExecError checks the given error for an exec.ExitError error and
+// sets the same podman exit code as the error.
+// No error will be returned in this case to make sure things like podman
+// unshare false work correctly without extra output.
+// When the exec file does not exists we set the exit code to 127, for
+// permission errors 126 is used as exit code. In this case we still return
+// the error so the user gets an error message.
+// If the error is nil it returns nil.
+func HandleOSExecError(err error) error {
+ if err == nil {
+ return nil
+ }
+ var exitError *exec.ExitError
+ if errors.As(err, &exitError) {
+ // the user command inside the unshare/ssh env has failed
+ // we set the exit code, do not return the error to the user
+ // otherwise "exit status X" will be printed
+ registry.SetExitCode(exitError.ExitCode())
+ return nil
+ }
+ // cmd.Run() can return fs.ErrNotExist, fs.ErrPermission or exec.ErrNotFound
+ // follow podman run/exec standard with the exit codes
+ if errors.Is(err, os.ErrNotExist) || errors.Is(err, exec.ErrNotFound) {
+ registry.SetExitCode(127)
+ } else if errors.Is(err, os.ErrPermission) {
+ registry.SetExitCode(126)
+ }
+ return err
+}
diff --git a/cmd/podman/utils/signals_linux.go b/cmd/podman/utils/signals_linux.go
deleted file mode 100644
index dd0507c0e..000000000
--- a/cmd/podman/utils/signals_linux.go
+++ /dev/null
@@ -1,15 +0,0 @@
-//go:build !windows
-// +build !windows
-
-package utils
-
-import (
- "os"
-
- "golang.org/x/sys/unix"
-)
-
-// Platform specific signal synonyms
-var (
- SIGHUP os.Signal = unix.SIGHUP
-)
diff --git a/cmd/podman/utils/signals_windows.go b/cmd/podman/utils/signals_windows.go
deleted file mode 100644
index e6fcc1b32..000000000
--- a/cmd/podman/utils/signals_windows.go
+++ /dev/null
@@ -1,15 +0,0 @@
-//go:build windows
-// +build windows
-
-package utils
-
-import (
- "os"
-
- "golang.org/x/sys/windows"
-)
-
-// Platform specific signal synonyms
-var (
- SIGHUP os.Signal = windows.SIGHUP
-)
diff --git a/cmd/podman/validate/args.go b/cmd/podman/validate/args.go
index 669456bd3..b9b468d34 100644
--- a/cmd/podman/validate/args.go
+++ b/cmd/podman/validate/args.go
@@ -50,89 +50,44 @@ func IDOrLatestArgs(cmd *cobra.Command, args []string) error {
return nil
}
-// TODO: the two functions CheckAllLatestAndCIDFile and CheckAllLatestAndPodIDFile are almost identical.
-// It may be worth looking into generalizing the two a bit more and share code but time is scarce and
-// we only live once.
-
-// CheckAllLatestAndCIDFile checks that --all and --latest are used correctly.
-// If cidfile is set, also check for the --cidfile flag.
+// CheckAllLatestAndCIDFile checks that --all and --latest are used correctly for containers and pods
+// If idFileFlag is set is set, also checks for the --cidfile or --pod-id-file flag.
+// Note: this has been deprecated, use CheckAllLatestAndIDFile instead
func CheckAllLatestAndCIDFile(c *cobra.Command, args []string, ignoreArgLen bool, cidfile bool) error {
- var specifiedLatest bool
- argLen := len(args)
- if !registry.IsRemote() {
- specifiedLatest, _ = c.Flags().GetBool("latest")
- if c.Flags().Lookup("all") == nil || c.Flags().Lookup("latest") == nil {
- if !cidfile {
- return errors.New("unable to lookup values for 'latest' or 'all'")
- } else if c.Flags().Lookup("cidfile") == nil {
- return errors.New("unable to lookup values for 'latest', 'all' or 'cidfile'")
- }
- }
- }
-
- specifiedAll, _ := c.Flags().GetBool("all")
- specifiedCIDFile := false
- if cid, _ := c.Flags().GetStringArray("cidfile"); len(cid) > 0 {
- specifiedCIDFile = true
- }
-
- if specifiedCIDFile && (specifiedAll || specifiedLatest) {
- return errors.Errorf("--all, --latest and --cidfile cannot be used together")
- } else if specifiedAll && specifiedLatest {
- return errors.Errorf("--all and --latest cannot be used together")
- }
-
- if (argLen > 0) && specifiedAll {
- return errors.Errorf("no arguments are needed with --all")
- }
-
- if ignoreArgLen {
- return nil
- }
-
- if argLen > 0 {
- if specifiedLatest {
- return errors.Errorf("--latest and containers cannot be used together")
- } else if cidfile && (specifiedLatest || specifiedCIDFile) {
- return errors.Errorf("no arguments are needed with --latest or --cidfile")
- }
- }
-
- if specifiedCIDFile {
- return nil
- }
-
- if argLen < 1 && !specifiedAll && !specifiedLatest && !specifiedCIDFile {
- return errors.Errorf("you must provide at least one name or id")
- }
- return nil
+ return CheckAllLatestAndIDFile(c, args, ignoreArgLen, "cidfile")
}
// CheckAllLatestAndPodIDFile checks that --all and --latest are used correctly.
// If withIDFile is set, also check for the --pod-id-file flag.
+// Note: this has been deprecated, use CheckAllLatestAndIDFile instead
func CheckAllLatestAndPodIDFile(c *cobra.Command, args []string, ignoreArgLen bool, withIDFile bool) error {
+ return CheckAllLatestAndIDFile(c, args, ignoreArgLen, "pod-id-file")
+}
+
+// CheckAllLatestAndIDFile checks that --all and --latest are used correctly for containers and pods
+// If idFileFlag is set is set, also checks for the --cidfile or --pod-id-file flag.
+func CheckAllLatestAndIDFile(c *cobra.Command, args []string, ignoreArgLen bool, idFileFlag string) error {
var specifiedLatest bool
argLen := len(args)
if !registry.IsRemote() {
- // remote clients have no latest flag
specifiedLatest, _ = c.Flags().GetBool("latest")
if c.Flags().Lookup("all") == nil || c.Flags().Lookup("latest") == nil {
- if !withIDFile {
+ if idFileFlag == "" {
return errors.New("unable to lookup values for 'latest' or 'all'")
- } else if c.Flags().Lookup("pod-id-file") == nil {
- return errors.New("unable to lookup values for 'latest', 'all' or 'pod-id-file'")
+ } else if c.Flags().Lookup(idFileFlag) == nil {
+ return errors.Errorf("unable to lookup values for 'latest', 'all', or '%s'", idFileFlag)
}
}
}
specifiedAll, _ := c.Flags().GetBool("all")
- specifiedPodIDFile := false
- if pid, _ := c.Flags().GetStringArray("pod-id-file"); len(pid) > 0 {
- specifiedPodIDFile = true
+ specifiedIDFile := false
+ if cid, _ := c.Flags().GetStringArray(idFileFlag); len(cid) > 0 {
+ specifiedIDFile = true
}
- if specifiedPodIDFile && (specifiedAll || specifiedLatest) {
- return errors.Errorf("--all, --latest and --pod-id-file cannot be used together")
+ if specifiedIDFile && (specifiedAll || specifiedLatest) {
+ return errors.Errorf("--all, --latest, and --%s cannot be used together", idFileFlag)
} else if specifiedAll && specifiedLatest {
return errors.Errorf("--all and --latest cannot be used together")
}
@@ -147,17 +102,17 @@ func CheckAllLatestAndPodIDFile(c *cobra.Command, args []string, ignoreArgLen bo
if argLen > 0 {
if specifiedLatest {
- return errors.Errorf("--latest and pods cannot be used together")
- } else if withIDFile && (specifiedLatest || specifiedPodIDFile) {
- return errors.Errorf("no arguments are needed with --latest or --pod-id-file")
+ return errors.Errorf("--latest and containers cannot be used together")
+ } else if idFileFlag != "" && (specifiedLatest || specifiedIDFile) {
+ return errors.Errorf("no arguments are needed with --latest or --%s", idFileFlag)
}
}
- if specifiedPodIDFile {
+ if specifiedIDFile {
return nil
}
- if argLen < 1 && !specifiedAll && !specifiedLatest && !specifiedPodIDFile {
+ if argLen < 1 && !specifiedAll && !specifiedLatest && !specifiedIDFile {
return errors.Errorf("you must provide at least one name or id")
}
return nil
diff --git a/cmd/podman/volumes/create.go b/cmd/podman/volumes/create.go
index 1668c72de..b47ae16ce 100644
--- a/cmd/podman/volumes/create.go
+++ b/cmd/podman/volumes/create.go
@@ -17,6 +17,7 @@ var (
createCommand = &cobra.Command{
Use: "create [options] [NAME]",
+ Args: cobra.MaximumNArgs(1),
Short: "Create a new volume",
Long: createDescription,
RunE: create,
@@ -59,9 +60,6 @@ func create(cmd *cobra.Command, args []string) error {
var (
err error
)
- if len(args) > 1 {
- return errors.Errorf("too many arguments, create takes at most 1 argument")
- }
if len(args) > 0 {
createOpts.Name = args[0]
}
diff --git a/cmd/podman/volumes/export.go b/cmd/podman/volumes/export.go
index 5086323f9..113f79a0b 100644
--- a/cmd/podman/volumes/export.go
+++ b/cmd/podman/volumes/export.go
@@ -8,6 +8,7 @@ import (
"github.com/containers/podman/v4/cmd/podman/common"
"github.com/containers/podman/v4/cmd/podman/registry"
"github.com/containers/podman/v4/pkg/domain/entities"
+ "github.com/containers/podman/v4/pkg/errorhandling"
"github.com/containers/podman/v4/utils"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -58,10 +59,13 @@ func export(cmd *cobra.Command, args []string) error {
return errors.New("expects output path, use --output=[path]")
}
inspectOpts.Type = common.VolumeType
- volumeData, _, err := containerEngine.VolumeInspect(ctx, args, inspectOpts)
+ volumeData, errs, err := containerEngine.VolumeInspect(ctx, args, inspectOpts)
if err != nil {
return err
}
+ if len(errs) > 0 {
+ return errorhandling.JoinErrors(errs)
+ }
if len(volumeData) < 1 {
return errors.New("no volume data found")
}
diff --git a/cmd/podman/volumes/import.go b/cmd/podman/volumes/import.go
index 988c5536d..76a311643 100644
--- a/cmd/podman/volumes/import.go
+++ b/cmd/podman/volumes/import.go
@@ -8,6 +8,7 @@ import (
"github.com/containers/podman/v4/cmd/podman/parse"
"github.com/containers/podman/v4/cmd/podman/registry"
"github.com/containers/podman/v4/pkg/domain/entities"
+ "github.com/containers/podman/v4/pkg/errorhandling"
"github.com/containers/podman/v4/utils"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@@ -60,10 +61,14 @@ func importVol(cmd *cobra.Command, args []string) error {
}
inspectOpts.Type = common.VolumeType
- volumeData, _, err := containerEngine.VolumeInspect(ctx, volumes, inspectOpts)
+ inspectOpts.Type = common.VolumeType
+ volumeData, errs, err := containerEngine.VolumeInspect(ctx, volumes, inspectOpts)
if err != nil {
return err
}
+ if len(errs) > 0 {
+ return errorhandling.JoinErrors(errs)
+ }
if len(volumeData) < 1 {
return errors.New("no volume data found")
}