summaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/api/handlers/compat/exec.go4
-rw-r--r--pkg/api/handlers/libpod/containers.go147
-rw-r--r--pkg/bindings/containers/checkpoint.go49
-rw-r--r--pkg/bindings/containers/types.go11
-rw-r--r--pkg/bindings/containers/types_checkpoint_options.go60
-rw-r--r--pkg/bindings/containers/types_restore_options.go60
-rw-r--r--pkg/bindings/test/common_test.go2
-rw-r--r--pkg/checkpoint/checkpoint_restore.go13
-rw-r--r--pkg/domain/entities/containers.go4
-rw-r--r--pkg/domain/infra/abi/containers.go4
-rw-r--r--pkg/domain/infra/tunnel/containers.go40
-rw-r--r--pkg/machine/ignition.go2
-rw-r--r--pkg/machine/qemu/options_darwin_arm64.go2
-rw-r--r--pkg/rootless/rootless_linux.c309
-rw-r--r--pkg/specgen/generate/container_create.go63
-rw-r--r--pkg/specgen/generate/pod_create.go13
-rw-r--r--pkg/specgenutil/util.go54
-rw-r--r--pkg/specgenutil/volumes.go2
-rw-r--r--pkg/util/filters.go25
-rw-r--r--pkg/util/mountOpts.go1
20 files changed, 545 insertions, 320 deletions
diff --git a/pkg/api/handlers/compat/exec.go b/pkg/api/handlers/compat/exec.go
index ea61a1013..76f720bf2 100644
--- a/pkg/api/handlers/compat/exec.go
+++ b/pkg/api/handlers/compat/exec.go
@@ -12,7 +12,7 @@ import (
"github.com/containers/podman/v3/pkg/api/handlers/utils"
"github.com/containers/podman/v3/pkg/api/server/idle"
api "github.com/containers/podman/v3/pkg/api/types"
- "github.com/containers/podman/v3/pkg/specgen/generate"
+ "github.com/containers/podman/v3/pkg/specgenutil"
"github.com/gorilla/mux"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -65,7 +65,7 @@ func ExecCreateHandler(w http.ResponseWriter, r *http.Request) {
return
}
// Automatically log to syslog if the server has log-level=debug set
- exitCommandArgs, err := generate.CreateExitCommandArgs(storageConfig, runtimeConfig, logrus.IsLevelEnabled(logrus.DebugLevel), true, true)
+ exitCommandArgs, err := specgenutil.CreateExitCommandArgs(storageConfig, runtimeConfig, logrus.IsLevelEnabled(logrus.DebugLevel), true, true)
if err != nil {
utils.InternalServerError(w, err)
return
diff --git a/pkg/api/handlers/libpod/containers.go b/pkg/api/handlers/libpod/containers.go
index 3aeebc334..d5da22a91 100644
--- a/pkg/api/handlers/libpod/containers.go
+++ b/pkg/api/handlers/libpod/containers.go
@@ -1,9 +1,11 @@
package libpod
import (
+ "fmt"
"io/ioutil"
"net/http"
"os"
+ "strings"
"github.com/containers/podman/v3/libpod"
"github.com/containers/podman/v3/libpod/define"
@@ -206,7 +208,9 @@ func ShowMountedContainers(w http.ResponseWriter, r *http.Request) {
}
func Checkpoint(w http.ResponseWriter, r *http.Request) {
- var targetFile string
+ runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
+ containerEngine := abi.ContainerEngine{Libpod: runtime}
+
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
query := struct {
Keep bool `schema:"keep"`
@@ -215,6 +219,8 @@ func Checkpoint(w http.ResponseWriter, r *http.Request) {
Export bool `schema:"export"`
IgnoreRootFS bool `schema:"ignoreRootFS"`
PrintStats bool `schema:"printStats"`
+ PreCheckpoint bool `schema:"preCheckpoint"`
+ WithPrevious bool `schema:"withPrevious"`
}{
// override any golang type defaults
}
@@ -224,66 +230,70 @@ func Checkpoint(w http.ResponseWriter, r *http.Request) {
errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
return
}
+
name := utils.GetName(r)
- runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
- ctr, err := runtime.LookupContainer(name)
- if err != nil {
+ if _, err := runtime.LookupContainer(name); err != nil {
utils.ContainerNotFound(w, name, err)
return
}
+ names := []string{name}
+
+ options := entities.CheckpointOptions{
+ Keep: query.Keep,
+ LeaveRunning: query.LeaveRunning,
+ TCPEstablished: query.TCPEstablished,
+ IgnoreRootFS: query.IgnoreRootFS,
+ PrintStats: query.PrintStats,
+ PreCheckPoint: query.PreCheckpoint,
+ WithPrevious: query.WithPrevious,
+ }
+
if query.Export {
- tmpFile, err := ioutil.TempFile("", "checkpoint")
+ f, err := ioutil.TempFile("", "checkpoint")
if err != nil {
utils.InternalServerError(w, err)
return
}
- defer os.Remove(tmpFile.Name())
- if err := tmpFile.Close(); err != nil {
+ defer os.Remove(f.Name())
+ if err := f.Close(); err != nil {
utils.InternalServerError(w, err)
return
}
- targetFile = tmpFile.Name()
- }
- options := libpod.ContainerCheckpointOptions{
- Keep: query.Keep,
- KeepRunning: query.LeaveRunning,
- TCPEstablished: query.TCPEstablished,
- IgnoreRootfs: query.IgnoreRootFS,
- PrintStats: query.PrintStats,
- }
- if query.Export {
- options.TargetFile = targetFile
+ options.Export = f.Name()
}
- criuStatistics, runtimeCheckpointDuration, err := ctr.Checkpoint(r.Context(), options)
+
+ reports, err := containerEngine.ContainerCheckpoint(r.Context(), names, options)
if err != nil {
utils.InternalServerError(w, err)
return
}
- if query.Export {
- f, err := os.Open(targetFile)
- if err != nil {
- utils.InternalServerError(w, err)
+
+ if !query.Export {
+ if len(reports) != 1 {
+ utils.InternalServerError(w, fmt.Errorf("expected 1 restore report but got %d", len(reports)))
return
}
- defer f.Close()
- utils.WriteResponse(w, http.StatusOK, f)
+ if reports[0].Err != nil {
+ utils.InternalServerError(w, reports[0].Err)
+ return
+ }
+ utils.WriteResponse(w, http.StatusOK, reports[0])
+ return
+ }
+
+ f, err := os.Open(options.Export)
+ if err != nil {
+ utils.InternalServerError(w, err)
return
}
- utils.WriteResponse(
- w,
- http.StatusOK,
- entities.CheckpointReport{
- Id: ctr.ID(),
- RuntimeDuration: runtimeCheckpointDuration,
- CRIUStatistics: criuStatistics,
- },
- )
+ defer f.Close()
+ utils.WriteResponse(w, http.StatusOK, f)
}
func Restore(w http.ResponseWriter, r *http.Request) {
- var (
- targetFile string
- )
+ runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
+ containerEngine := abi.ContainerEngine{Libpod: runtime}
+
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
query := struct {
Keep bool `schema:"keep"`
@@ -295,6 +305,7 @@ func Restore(w http.ResponseWriter, r *http.Request) {
IgnoreStaticIP bool `schema:"ignoreStaticIP"`
IgnoreStaticMAC bool `schema:"ignoreStaticMAC"`
PrintStats bool `schema:"printStats"`
+ PublishPorts string `schema:"publishPorts"`
}{
// override any golang type defaults
}
@@ -303,53 +314,55 @@ func Restore(w http.ResponseWriter, r *http.Request) {
errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
return
}
- name := utils.GetName(r)
- runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
- ctr, err := runtime.LookupContainer(name)
- if err != nil {
- utils.ContainerNotFound(w, name, err)
- return
+
+ options := entities.RestoreOptions{
+ Name: query.Name,
+ Keep: query.Keep,
+ TCPEstablished: query.TCPEstablished,
+ IgnoreRootFS: query.IgnoreRootFS,
+ IgnoreVolumes: query.IgnoreVolumes,
+ IgnoreStaticIP: query.IgnoreStaticIP,
+ IgnoreStaticMAC: query.IgnoreStaticMAC,
+ PrintStats: query.PrintStats,
+ PublishPorts: strings.Fields(query.PublishPorts),
}
+
+ var names []string
if query.Import {
t, err := ioutil.TempFile("", "restore")
if err != nil {
utils.InternalServerError(w, err)
return
}
- defer t.Close()
+ defer os.Remove(t.Name())
if err := compat.SaveFromBody(t, r); err != nil {
utils.InternalServerError(w, err)
return
}
- targetFile = t.Name()
+ options.Import = t.Name()
+ } else {
+ name := utils.GetName(r)
+ if _, err := runtime.LookupContainer(name); err != nil {
+ utils.ContainerNotFound(w, name, err)
+ return
+ }
+ names = []string{name}
}
- options := libpod.ContainerCheckpointOptions{
- Keep: query.Keep,
- TCPEstablished: query.TCPEstablished,
- IgnoreRootfs: query.IgnoreRootFS,
- IgnoreStaticIP: query.IgnoreStaticIP,
- IgnoreStaticMAC: query.IgnoreStaticMAC,
- PrintStats: query.PrintStats,
- }
- if query.Import {
- options.TargetFile = targetFile
- options.Name = query.Name
- }
- criuStatistics, runtimeRestoreDuration, err := ctr.Restore(r.Context(), options)
+ reports, err := containerEngine.ContainerRestore(r.Context(), names, options)
if err != nil {
utils.InternalServerError(w, err)
return
}
- utils.WriteResponse(
- w,
- http.StatusOK,
- entities.RestoreReport{
- Id: ctr.ID(),
- RuntimeDuration: runtimeRestoreDuration,
- CRIUStatistics: criuStatistics,
- },
- )
+ if len(reports) != 1 {
+ utils.InternalServerError(w, fmt.Errorf("expected 1 restore report but got %d", len(reports)))
+ return
+ }
+ if reports[0].Err != nil {
+ utils.InternalServerError(w, reports[0].Err)
+ return
+ }
+ utils.WriteResponse(w, http.StatusOK, reports[0])
}
func InitContainer(w http.ResponseWriter, r *http.Request) {
diff --git a/pkg/bindings/containers/checkpoint.go b/pkg/bindings/containers/checkpoint.go
index 2ad2c6931..7b4ec093d 100644
--- a/pkg/bindings/containers/checkpoint.go
+++ b/pkg/bindings/containers/checkpoint.go
@@ -2,7 +2,9 @@ package containers
import (
"context"
+ "io"
"net/http"
+ "os"
"github.com/containers/podman/v3/pkg/bindings"
"github.com/containers/podman/v3/pkg/domain/entities"
@@ -23,13 +25,34 @@ func Checkpoint(ctx context.Context, nameOrID string, options *CheckpointOptions
if err != nil {
return nil, err
}
+
+ // "export" is a bool for the server so override it in the parameters
+ // if set.
+ export := false
+ if options.Export != nil && *options.Export != "" {
+ export = true
+ params.Set("export", "true")
+ }
response, err := conn.DoRequest(ctx, nil, http.MethodPost, "/containers/%s/checkpoint", params, nil, nameOrID)
if err != nil {
return nil, err
}
defer response.Body.Close()
- return &report, response.Process(&report)
+ if !export {
+ return &report, response.Process(&report)
+ }
+
+ f, err := os.OpenFile(*options.Export, os.O_RDWR|os.O_CREATE, 0600)
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+ if _, err := io.Copy(f, response.Body); err != nil {
+ return nil, err
+ }
+
+ return &entities.CheckpointReport{}, nil
}
// Restore restores a checkpointed container to running. The container is identified by the nameOrID option. All
@@ -47,12 +70,26 @@ func Restore(ctx context.Context, nameOrID string, options *RestoreOptions) (*en
if err != nil {
return nil, err
}
- // The import key is a reserved golang term
- params.Del("ImportArchive")
- if i := options.GetImportAchive(); options.Changed("ImportArchive") {
- params.Set("import", i)
+
+ for _, p := range options.PublishPorts {
+ params.Add("publishPorts", p)
+ }
+
+ params.Del("ImportArchive") // The import key is a reserved golang term
+
+ // Open the to-be-imported archive if needed.
+ var r io.Reader
+ if i := options.GetImportAchive(); i != "" {
+ params.Set("import", "true")
+ r, err = os.Open(i)
+ if err != nil {
+ return nil, err
+ }
+ // Hard-code the name since it will be ignored in any case.
+ nameOrID = "import"
}
- response, err := conn.DoRequest(ctx, nil, http.MethodPost, "/containers/%s/restore", params, nil, nameOrID)
+
+ response, err := conn.DoRequest(ctx, r, http.MethodPost, "/containers/%s/restore", params, nil, nameOrID)
if err != nil {
return nil, err
}
diff --git a/pkg/bindings/containers/types.go b/pkg/bindings/containers/types.go
index 3a7d5a4c7..81a53a549 100644
--- a/pkg/bindings/containers/types.go
+++ b/pkg/bindings/containers/types.go
@@ -50,12 +50,17 @@ type CheckpointOptions struct {
Keep *bool
LeaveRunning *bool
TCPEstablished *bool
+ PrintStats *bool
+ PreCheckpoint *bool
+ WithPrevious *bool
+ FileLocks *bool
}
//go:generate go run ../generator/generator.go RestoreOptions
// RestoreOptions are optional options for restoring containers
type RestoreOptions struct {
IgnoreRootfs *bool
+ IgnoreVolumes *bool
IgnoreStaticIP *bool
IgnoreStaticMAC *bool
ImportAchive *string
@@ -63,6 +68,9 @@ type RestoreOptions struct {
Name *string
TCPEstablished *bool
Pod *string
+ PrintStats *bool
+ PublishPorts []string
+ FileLocks *bool
}
//go:generate go run ../generator/generator.go CreateOptions
@@ -86,7 +94,8 @@ type ExecInspectOptions struct{}
//go:generate go run ../generator/generator.go ExecStartOptions
// ExecStartOptions are optional options for starting
// exec sessions
-type ExecStartOptions struct{}
+type ExecStartOptions struct {
+}
//go:generate go run ../generator/generator.go HealthCheckOptions
// HealthCheckOptions are optional options for checking
diff --git a/pkg/bindings/containers/types_checkpoint_options.go b/pkg/bindings/containers/types_checkpoint_options.go
index 7b28c4045..391748d76 100644
--- a/pkg/bindings/containers/types_checkpoint_options.go
+++ b/pkg/bindings/containers/types_checkpoint_options.go
@@ -91,3 +91,63 @@ func (o *CheckpointOptions) GetTCPEstablished() bool {
}
return *o.TCPEstablished
}
+
+// WithPrintStats set field PrintStats to given value
+func (o *CheckpointOptions) WithPrintStats(value bool) *CheckpointOptions {
+ o.PrintStats = &value
+ return o
+}
+
+// GetPrintStats returns value of field PrintStats
+func (o *CheckpointOptions) GetPrintStats() bool {
+ if o.PrintStats == nil {
+ var z bool
+ return z
+ }
+ return *o.PrintStats
+}
+
+// WithPreCheckpoint set field PreCheckpoint to given value
+func (o *CheckpointOptions) WithPreCheckpoint(value bool) *CheckpointOptions {
+ o.PreCheckpoint = &value
+ return o
+}
+
+// GetPreCheckpoint returns value of field PreCheckpoint
+func (o *CheckpointOptions) GetPreCheckpoint() bool {
+ if o.PreCheckpoint == nil {
+ var z bool
+ return z
+ }
+ return *o.PreCheckpoint
+}
+
+// WithWithPrevious set field WithPrevious to given value
+func (o *CheckpointOptions) WithWithPrevious(value bool) *CheckpointOptions {
+ o.WithPrevious = &value
+ return o
+}
+
+// GetWithPrevious returns value of field WithPrevious
+func (o *CheckpointOptions) GetWithPrevious() bool {
+ if o.WithPrevious == nil {
+ var z bool
+ return z
+ }
+ return *o.WithPrevious
+}
+
+// WithFileLocks set field FileLocks to given value
+func (o *CheckpointOptions) WithFileLocks(value bool) *CheckpointOptions {
+ o.FileLocks = &value
+ return o
+}
+
+// GetFileLocks returns value of field FileLocks
+func (o *CheckpointOptions) GetFileLocks() bool {
+ if o.FileLocks == nil {
+ var z bool
+ return z
+ }
+ return *o.FileLocks
+}
diff --git a/pkg/bindings/containers/types_restore_options.go b/pkg/bindings/containers/types_restore_options.go
index 6eea108f4..7af2bba32 100644
--- a/pkg/bindings/containers/types_restore_options.go
+++ b/pkg/bindings/containers/types_restore_options.go
@@ -32,6 +32,21 @@ func (o *RestoreOptions) GetIgnoreRootfs() bool {
return *o.IgnoreRootfs
}
+// WithIgnoreVolumes set field IgnoreVolumes to given value
+func (o *RestoreOptions) WithIgnoreVolumes(value bool) *RestoreOptions {
+ o.IgnoreVolumes = &value
+ return o
+}
+
+// GetIgnoreVolumes returns value of field IgnoreVolumes
+func (o *RestoreOptions) GetIgnoreVolumes() bool {
+ if o.IgnoreVolumes == nil {
+ var z bool
+ return z
+ }
+ return *o.IgnoreVolumes
+}
+
// WithIgnoreStaticIP set field IgnoreStaticIP to given value
func (o *RestoreOptions) WithIgnoreStaticIP(value bool) *RestoreOptions {
o.IgnoreStaticIP = &value
@@ -136,3 +151,48 @@ func (o *RestoreOptions) GetPod() string {
}
return *o.Pod
}
+
+// WithPrintStats set field PrintStats to given value
+func (o *RestoreOptions) WithPrintStats(value bool) *RestoreOptions {
+ o.PrintStats = &value
+ return o
+}
+
+// GetPrintStats returns value of field PrintStats
+func (o *RestoreOptions) GetPrintStats() bool {
+ if o.PrintStats == nil {
+ var z bool
+ return z
+ }
+ return *o.PrintStats
+}
+
+// WithPublishPorts set field PublishPorts to given value
+func (o *RestoreOptions) WithPublishPorts(value []string) *RestoreOptions {
+ o.PublishPorts = value
+ return o
+}
+
+// GetPublishPorts returns value of field PublishPorts
+func (o *RestoreOptions) GetPublishPorts() []string {
+ if o.PublishPorts == nil {
+ var z []string
+ return z
+ }
+ return o.PublishPorts
+}
+
+// WithFileLocks set field FileLocks to given value
+func (o *RestoreOptions) WithFileLocks(value bool) *RestoreOptions {
+ o.FileLocks = &value
+ return o
+}
+
+// GetFileLocks returns value of field FileLocks
+func (o *RestoreOptions) GetFileLocks() bool {
+ if o.FileLocks == nil {
+ var z bool
+ return z
+ }
+ return *o.FileLocks
+}
diff --git a/pkg/bindings/test/common_test.go b/pkg/bindings/test/common_test.go
index d996595bf..233666a48 100644
--- a/pkg/bindings/test/common_test.go
+++ b/pkg/bindings/test/common_test.go
@@ -151,7 +151,7 @@ func createTempDirInTempDir() (string, error) {
}
func (b *bindingTest) startAPIService() *gexec.Session {
- cmd := []string{"--log-level=debug", "--events-backend=file", "system", "service", "--timeout=0", b.sock}
+ cmd := []string{"--log-level=debug", "system", "service", "--timeout=0", b.sock}
session := b.runPodman(cmd)
sock := strings.TrimPrefix(b.sock, "unix://")
diff --git a/pkg/checkpoint/checkpoint_restore.go b/pkg/checkpoint/checkpoint_restore.go
index da82c9745..85fe6a77e 100644
--- a/pkg/checkpoint/checkpoint_restore.go
+++ b/pkg/checkpoint/checkpoint_restore.go
@@ -16,6 +16,7 @@ import (
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/errorhandling"
"github.com/containers/podman/v3/pkg/specgen/generate"
+ "github.com/containers/podman/v3/pkg/specgenutil"
"github.com/containers/storage/pkg/archive"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
@@ -195,7 +196,12 @@ func CRImportCheckpoint(ctx context.Context, runtime *libpod.Runtime, restoreOpt
}
if len(restoreOptions.PublishPorts) > 0 {
- ports, err := generate.ParsePortMapping(restoreOptions.PublishPorts, nil)
+ pubPorts, err := specgenutil.CreatePortBindings(restoreOptions.PublishPorts)
+ if err != nil {
+ return nil, err
+ }
+
+ ports, err := generate.ParsePortMapping(pubPorts, nil)
if err != nil {
return nil, err
}
@@ -233,11 +239,6 @@ func CRImportCheckpoint(ctx context.Context, runtime *libpod.Runtime, restoreOpt
}
}
- // Check if the ExitCommand points to the correct container ID
- if containerConfig.ExitCommand[len(containerConfig.ExitCommand)-1] != containerConfig.ID {
- return nil, errors.Errorf("'ExitCommandID' uses ID %s instead of container ID %s", containerConfig.ExitCommand[len(containerConfig.ExitCommand)-1], containerConfig.ID)
- }
-
containers = append(containers, container)
return containers, nil
}
diff --git a/pkg/domain/entities/containers.go b/pkg/domain/entities/containers.go
index 8b7cd62d9..1677c067f 100644
--- a/pkg/domain/entities/containers.go
+++ b/pkg/domain/entities/containers.go
@@ -191,6 +191,7 @@ type CheckpointOptions struct {
WithPrevious bool
Compression archive.Compression
PrintStats bool
+ FileLocks bool
}
type CheckpointReport struct {
@@ -212,9 +213,10 @@ type RestoreOptions struct {
Name string
TCPEstablished bool
ImportPrevious string
- PublishPorts []nettypes.PortMapping
+ PublishPorts []string
Pod string
PrintStats bool
+ FileLocks bool
}
type RestoreReport struct {
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
index 69c628669..631eb3a43 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -29,6 +29,7 @@ import (
"github.com/containers/podman/v3/pkg/signal"
"github.com/containers/podman/v3/pkg/specgen"
"github.com/containers/podman/v3/pkg/specgen/generate"
+ "github.com/containers/podman/v3/pkg/specgenutil"
"github.com/containers/podman/v3/pkg/util"
"github.com/containers/storage"
"github.com/pkg/errors"
@@ -516,6 +517,7 @@ func (ic *ContainerEngine) ContainerCheckpoint(ctx context.Context, namesOrIds [
WithPrevious: options.WithPrevious,
Compression: options.Compression,
PrintStats: options.PrintStats,
+ FileLocks: options.FileLocks,
}
if options.All {
@@ -656,7 +658,7 @@ func makeExecConfig(options entities.ExecOptions, rt *libpod.Runtime) (*libpod.E
return nil, errors.Wrapf(err, "error retrieving Libpod configuration to build exec exit command")
}
// TODO: Add some ability to toggle syslog
- exitCommandArgs, err := generate.CreateExitCommandArgs(storageConfig, runtimeConfig, false, false, true)
+ exitCommandArgs, err := specgenutil.CreateExitCommandArgs(storageConfig, runtimeConfig, logrus.IsLevelEnabled(logrus.DebugLevel), false, true)
if err != nil {
return nil, errors.Wrapf(err, "error constructing exit command for exec session")
}
diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go
index 5b5a1912c..2127f8749 100644
--- a/pkg/domain/infra/tunnel/containers.go
+++ b/pkg/domain/infra/tunnel/containers.go
@@ -302,6 +302,17 @@ func (ic *ContainerEngine) ContainerExport(ctx context.Context, nameOrID string,
}
func (ic *ContainerEngine) ContainerCheckpoint(ctx context.Context, namesOrIds []string, opts entities.CheckpointOptions) ([]*entities.CheckpointReport, error) {
+ options := new(containers.CheckpointOptions)
+ options.WithFileLocks(opts.FileLocks)
+ options.WithIgnoreRootfs(opts.IgnoreRootFS)
+ options.WithKeep(opts.Keep)
+ options.WithExport(opts.Export)
+ options.WithTCPEstablished(opts.TCPEstablished)
+ options.WithPrintStats(opts.PrintStats)
+ options.WithPreCheckpoint(opts.PreCheckPoint)
+ options.WithLeaveRunning(opts.LeaveRunning)
+ options.WithWithPrevious(opts.WithPrevious)
+
var (
err error
ctrs = []entities.ListContainer{}
@@ -325,19 +336,41 @@ func (ic *ContainerEngine) ContainerCheckpoint(ctx context.Context, namesOrIds [
}
}
reports := make([]*entities.CheckpointReport, 0, len(ctrs))
- options := new(containers.CheckpointOptions).WithExport(opts.Export).WithIgnoreRootfs(opts.IgnoreRootFS).WithKeep(opts.Keep)
- options.WithLeaveRunning(opts.LeaveRunning).WithTCPEstablished(opts.TCPEstablished)
for _, c := range ctrs {
report, err := containers.Checkpoint(ic.ClientCtx, c.ID, options)
if err != nil {
reports = append(reports, &entities.CheckpointReport{Id: c.ID, Err: err})
+ } else {
+ reports = append(reports, report)
}
- reports = append(reports, report)
}
return reports, nil
}
func (ic *ContainerEngine) ContainerRestore(ctx context.Context, namesOrIds []string, opts entities.RestoreOptions) ([]*entities.RestoreReport, error) {
+ if opts.ImportPrevious != "" {
+ return nil, fmt.Errorf("--import-previous is not supported on the remote client")
+ }
+
+ options := new(containers.RestoreOptions)
+ options.WithFileLocks(opts.FileLocks)
+ options.WithIgnoreRootfs(opts.IgnoreRootFS)
+ options.WithIgnoreVolumes(opts.IgnoreVolumes)
+ options.WithIgnoreStaticIP(opts.IgnoreStaticIP)
+ options.WithIgnoreStaticMAC(opts.IgnoreStaticMAC)
+ options.WithKeep(opts.Keep)
+ options.WithName(opts.Name)
+ options.WithTCPEstablished(opts.TCPEstablished)
+ options.WithPod(opts.Pod)
+ options.WithPrintStats(opts.PrintStats)
+ options.WithPublishPorts(opts.PublishPorts)
+
+ if opts.Import != "" {
+ options.WithImportAchive(opts.Import)
+ report, err := containers.Restore(ic.ClientCtx, "", options)
+ return []*entities.RestoreReport{report}, err
+ }
+
var (
err error
ctrs = []entities.ListContainer{}
@@ -360,7 +393,6 @@ func (ic *ContainerEngine) ContainerRestore(ctx context.Context, namesOrIds []st
}
}
reports := make([]*entities.RestoreReport, 0, len(ctrs))
- options := new(containers.RestoreOptions)
for _, c := range ctrs {
report, err := containers.Restore(ic.ClientCtx, c.ID, options)
if err != nil {
diff --git a/pkg/machine/ignition.go b/pkg/machine/ignition.go
index 42d729458..e19940b22 100644
--- a/pkg/machine/ignition.go
+++ b/pkg/machine/ignition.go
@@ -81,7 +81,7 @@ func NewIgnitionFile(ign DynamicIgnition) error {
// so a listening host knows it can being interacting with it
ready := `[Unit]
Requires=dev-virtio\\x2dports-%s.device
-After=remove-moby.service
+After=remove-moby.service sshd.socket sshd.service
OnFailure=emergency.target
OnFailureJobMode=isolate
[Service]
diff --git a/pkg/machine/qemu/options_darwin_arm64.go b/pkg/machine/qemu/options_darwin_arm64.go
index 43cd3d69d..727a275d2 100644
--- a/pkg/machine/qemu/options_darwin_arm64.go
+++ b/pkg/machine/qemu/options_darwin_arm64.go
@@ -24,7 +24,7 @@ func (v *MachineVM) addArchOptions() []string {
func (v *MachineVM) prepare() error {
ovmfDir := getOvmfDir(v.ImagePath, v.Name)
- cmd := []string{"dd", "if=/dev/zero", "conv=sync", "bs=1m", "count=64", "of=" + ovmfDir}
+ cmd := []string{"/bin/dd", "if=/dev/zero", "conv=sync", "bs=1m", "count=64", "of=" + ovmfDir}
return exec.Command(cmd[0], cmd[1:]...).Run()
}
diff --git a/pkg/rootless/rootless_linux.c b/pkg/rootless/rootless_linux.c
index 6ce4b1e29..e71d5d999 100644
--- a/pkg/rootless/rootless_linux.c
+++ b/pkg/rootless/rootless_linux.c
@@ -19,6 +19,33 @@
#include <sys/select.h>
#include <stdio.h>
+#define cleanup_free __attribute__ ((cleanup (cleanup_freep)))
+#define cleanup_close __attribute__ ((cleanup (cleanup_closep)))
+#define cleanup_dir __attribute__ ((cleanup (cleanup_dirp)))
+
+static inline void
+cleanup_freep (void *p)
+{
+ void **pp = (void **) p;
+ free (*pp);
+}
+
+static inline void
+cleanup_closep (void *p)
+{
+ int *pp = p;
+ if (*pp >= 0)
+ TEMP_FAILURE_RETRY (close (*pp));
+}
+
+static inline void
+cleanup_dirp (DIR **p)
+{
+ DIR *dir = *p;
+ if (dir)
+ closedir (dir);
+}
+
int rename_noreplace (int olddirfd, const char *oldpath, int newdirfd, const char *newpath)
{
int ret;
@@ -106,6 +133,11 @@ do_pause ()
for (i = 0; sig[i]; i++)
sigaction (sig[i], &act, NULL);
+ /* Attempt to execv catatonit to keep the pause process alive. */
+ execl ("/usr/libexec/podman/catatonit", "catatonit", "-P", NULL);
+ execl ("/usr/bin/catatonit", "catatonit", "-P", NULL);
+ /* and if the catatonit executable could not be found, fallback here... */
+
prctl (PR_SET_NAME, "podman pause", NULL, NULL, NULL);
while (1)
pause ();
@@ -114,8 +146,8 @@ do_pause ()
static char **
get_cmd_line_args ()
{
- int fd;
- char *buffer;
+ cleanup_free char *buffer = NULL;
+ cleanup_close int fd = -1;
size_t allocated;
size_t used = 0;
int ret;
@@ -134,10 +166,7 @@ get_cmd_line_args ()
{
ret = TEMP_FAILURE_RETRY (read (fd, buffer + used, allocated - used));
if (ret < 0)
- {
- free (buffer);
- return NULL;
- }
+ return NULL;
if (ret == 0)
break;
@@ -148,30 +177,21 @@ get_cmd_line_args ()
allocated += 512;
char *tmp = realloc (buffer, allocated);
if (tmp == NULL)
- {
- free (buffer);
- return NULL;
- }
+ return NULL;
buffer = tmp;
}
}
- close (fd);
for (i = 0; i < used; i++)
if (buffer[i] == '\0')
argc++;
if (argc == 0)
- {
- free (buffer);
- return NULL;
- }
+ return NULL;
argv = malloc (sizeof (char *) * (argc + 1));
if (argv == NULL)
- {
- free (buffer);
- return NULL;
- }
+ return NULL;
+
argc = 0;
argv[argc++] = buffer;
@@ -181,15 +201,19 @@ get_cmd_line_args ()
argv[argc] = NULL;
+ /* Move ownership. */
+ buffer = NULL;
+
return argv;
}
static bool
can_use_shortcut ()
{
- int argc;
- char **argv;
+ cleanup_free char **argv = NULL;
+ cleanup_free char *argv0 = NULL;
bool ret = true;
+ int argc;
#ifdef DISABLE_JOIN_SHORTCUT
return false;
@@ -199,12 +223,10 @@ can_use_shortcut ()
if (argv == NULL)
return false;
+ argv0 = argv[0];
+
if (strstr (argv[0], "podman") == NULL)
- {
- free (argv[0]);
- free (argv);
- return false;
- }
+ return false;
for (argc = 0; argv[argc]; argc++)
{
@@ -229,11 +251,25 @@ can_use_shortcut ()
}
}
- free (argv[0]);
- free (argv);
return ret;
}
+static int
+open_namespace (int pid_to_join, const char *ns_file)
+{
+ char ns_path[PATH_MAX];
+ int ret;
+
+ ret = snprintf (ns_path, PATH_MAX, "/proc/%d/ns/%s", pid_to_join, ns_file);
+ if (ret == PATH_MAX)
+ {
+ fprintf (stderr, "internal error: namespace path too long\n");
+ return -1;
+ }
+
+ return open (ns_path, O_CLOEXEC | O_RDONLY);
+}
+
int
is_fd_inherited(int fd)
{
@@ -250,8 +286,7 @@ static void __attribute__((constructor)) init()
const char *listen_pid;
const char *listen_fds;
const char *listen_fdnames;
-
- DIR *d;
+ cleanup_dir DIR *d = NULL;
pause = getenv ("_PODMAN_PAUSE");
if (pause && pause[0])
@@ -299,7 +334,6 @@ static void __attribute__((constructor)) init()
FD_SET (fd % FD_SETSIZE, &(open_files_set[fd / FD_SETSIZE]));
}
- closedir (d);
}
listen_pid = getenv("LISTEN_PID");
@@ -317,7 +351,7 @@ static void __attribute__((constructor)) init()
if (saved_systemd_listen_pid == NULL
|| saved_systemd_listen_fds == NULL)
{
- fprintf (stderr, "save socket listen environments error: %s\n", strerror (errno));
+ fprintf (stderr, "save socket listen environments error: %m\n");
_exit (EXIT_FAILURE);
}
}
@@ -327,73 +361,70 @@ static void __attribute__((constructor)) init()
xdg_runtime_dir = getenv ("XDG_RUNTIME_DIR");
if (geteuid () != 0 && xdg_runtime_dir && xdg_runtime_dir[0] && can_use_shortcut ())
{
- int r;
- int fd;
+ cleanup_free char *cwd = NULL;
+ cleanup_close int userns_fd = -1;
+ cleanup_close int mntns_fd = -1;
+ cleanup_close int fd = -1;
long pid;
char buf[12];
uid_t uid;
gid_t gid;
char path[PATH_MAX];
const char *const suffix = "/libpod/tmp/pause.pid";
- char *cwd = getcwd (NULL, 0);
char uid_fmt[16];
char gid_fmt[16];
size_t len;
+ int r;
+ cwd = getcwd (NULL, 0);
if (cwd == NULL)
{
- fprintf (stderr, "error getting current working directory: %s\n", strerror (errno));
+ fprintf (stderr, "error getting current working directory: %m\n");
_exit (EXIT_FAILURE);
}
len = snprintf (path, PATH_MAX, "%s%s", xdg_runtime_dir, suffix);
if (len >= PATH_MAX)
{
- fprintf (stderr, "invalid value for XDG_RUNTIME_DIR: %s", strerror (ENAMETOOLONG));
+ errno = ENAMETOOLONG;
+ fprintf (stderr, "invalid value for XDG_RUNTIME_DIR: %m");
exit (EXIT_FAILURE);
}
fd = open (path, O_RDONLY);
if (fd < 0)
- {
- free (cwd);
- return;
- }
+ return;
r = TEMP_FAILURE_RETRY (read (fd, buf, sizeof (buf) - 1));
- close (fd);
+
if (r < 0)
- {
- free (cwd);
- return;
- }
+ return;
buf[r] = '\0';
pid = strtol (buf, NULL, 10);
if (pid == LONG_MAX)
- {
- free (cwd);
- return;
- }
+ return;
uid = geteuid ();
gid = getegid ();
- sprintf (path, "/proc/%ld/ns/user", pid);
- fd = open (path, O_RDONLY);
- if (fd < 0 || setns (fd, 0) < 0)
- {
- free (cwd);
- return;
- }
- close (fd);
+ userns_fd = open_namespace (pid, "user");
+ if (userns_fd < 0)
+ return;
- /* Errors here cannot be ignored as we already joined a ns. */
- sprintf (path, "/proc/%ld/ns/mnt", pid);
- fd = open (path, O_RDONLY);
- if (fd < 0)
+ mntns_fd = open_namespace (pid, "mnt");
+ if (mntns_fd < 0)
+ return;
+
+ if (setns (userns_fd, 0) < 0)
+ return;
+
+ /* The user namespace was joined, after this point errors are
+ not recoverable anymore. */
+
+ if (setns (mntns_fd, 0) < 0)
{
- fprintf (stderr, "cannot open %s: %s", path, strerror (errno));
+ fprintf (stderr, "cannot join mount namespace for %ld: %m", pid);
exit (EXIT_FAILURE);
}
@@ -404,33 +435,24 @@ static void __attribute__((constructor)) init()
setenv ("_CONTAINERS_ROOTLESS_UID", uid_fmt, 1);
setenv ("_CONTAINERS_ROOTLESS_GID", gid_fmt, 1);
- r = setns (fd, 0);
- if (r < 0)
- {
- fprintf (stderr, "cannot join mount namespace for %ld: %s", pid, strerror (errno));
- exit (EXIT_FAILURE);
- }
- close (fd);
-
if (syscall_setresgid (0, 0, 0) < 0)
{
- fprintf (stderr, "cannot setresgid: %s\n", strerror (errno));
+ fprintf (stderr, "cannot setresgid: %m\n");
_exit (EXIT_FAILURE);
}
if (syscall_setresuid (0, 0, 0) < 0)
{
- fprintf (stderr, "cannot setresuid: %s\n", strerror (errno));
+ fprintf (stderr, "cannot setresuid: %m\n");
_exit (EXIT_FAILURE);
}
if (chdir (cwd) < 0)
{
- fprintf (stderr, "cannot chdir to %s: %s\n", cwd, strerror (errno));
+ fprintf (stderr, "cannot chdir to %s: %m\n", cwd);
_exit (EXIT_FAILURE);
}
- free (cwd);
rootless_uid_init = uid;
rootless_gid_init = gid;
}
@@ -529,7 +551,7 @@ create_pause_process (const char *pause_pid_file_path, char **argv)
fd = mkstemp (tmp_file_path);
if (fd < 0)
{
- fprintf (stderr, "error creating temporary file: %s\n", strerror (errno));
+ fprintf (stderr, "error creating temporary file: %m\n");
kill (pid, SIGKILL);
_exit (EXIT_FAILURE);
}
@@ -537,7 +559,7 @@ create_pause_process (const char *pause_pid_file_path, char **argv)
r = TEMP_FAILURE_RETRY (write (fd, pid_str, strlen (pid_str)));
if (r < 0)
{
- fprintf (stderr, "cannot write to file descriptor: %s\n", strerror (errno));
+ fprintf (stderr, "cannot write to file descriptor: %m\n");
kill (pid, SIGKILL);
_exit (EXIT_FAILURE);
}
@@ -555,7 +577,7 @@ create_pause_process (const char *pause_pid_file_path, char **argv)
r = TEMP_FAILURE_RETRY (write (p[1], "0", 1));
if (r < 0)
{
- fprintf (stderr, "cannot write to pipe: %s\n", strerror (errno));
+ fprintf (stderr, "cannot write to pipe: %m\n");
_exit (EXIT_FAILURE);
}
close (p[1]);
@@ -590,22 +612,6 @@ create_pause_process (const char *pause_pid_file_path, char **argv)
}
}
-static int
-open_namespace (int pid_to_join, const char *ns_file)
-{
- char ns_path[PATH_MAX];
- int ret;
-
- ret = snprintf (ns_path, PATH_MAX, "/proc/%d/ns/%s", pid_to_join, ns_file);
- if (ret == PATH_MAX)
- {
- fprintf (stderr, "internal error: namespace path too long\n");
- return -1;
- }
-
- return open (ns_path, O_CLOEXEC | O_RDONLY);
-}
-
static void
join_namespace_or_die (const char *name, int ns_fd)
{
@@ -619,18 +625,20 @@ join_namespace_or_die (const char *name, int ns_fd)
int
reexec_userns_join (int pid_to_join, char *pause_pid_file_path)
{
+ cleanup_close int userns_fd = -1;
+ cleanup_close int mntns_fd = -1;
+ cleanup_free char *cwd = NULL;
char uid[16];
char gid[16];
- char **argv;
+ cleanup_free char *argv0 = NULL;
+ cleanup_free char **argv = NULL;
int pid;
- int mnt_ns = -1;
- int user_ns = -1;
- char *cwd = getcwd (NULL, 0);
sigset_t sigset, oldsigset;
+ cwd = getcwd (NULL, 0);
if (cwd == NULL)
{
- fprintf (stderr, "error getting current working directory: %s\n", strerror (errno));
+ fprintf (stderr, "error getting current working directory: %m\n");
_exit (EXIT_FAILURE);
}
@@ -640,32 +648,27 @@ reexec_userns_join (int pid_to_join, char *pause_pid_file_path)
argv = get_cmd_line_args ();
if (argv == NULL)
{
- fprintf (stderr, "cannot read argv: %s\n", strerror (errno));
+ fprintf (stderr, "cannot read argv: %m\n");
_exit (EXIT_FAILURE);
}
- user_ns = open_namespace (pid_to_join, "user");
- if (user_ns < 0)
- return user_ns;
- mnt_ns = open_namespace (pid_to_join, "mnt");
- if (mnt_ns < 0)
- {
- close (user_ns);
- return mnt_ns;
- }
+ argv0 = argv[0];
+
+ userns_fd = open_namespace (pid_to_join, "user");
+ if (userns_fd < 0)
+ return userns_fd;
+ mntns_fd = open_namespace (pid_to_join, "mnt");
+ if (mntns_fd < 0)
+ return mntns_fd;
pid = fork ();
if (pid < 0)
- fprintf (stderr, "cannot fork: %s\n", strerror (errno));
+ fprintf (stderr, "cannot fork: %m\n");
if (pid)
{
int f;
- /* We passed down these fds, close them. */
- close (user_ns);
- close (mnt_ns);
-
for (f = 3; f <= open_files_max_fd; f++)
if (is_fd_inherited (f))
close (f);
@@ -681,22 +684,22 @@ reexec_userns_join (int pid_to_join, char *pause_pid_file_path)
if (sigfillset (&sigset) < 0)
{
- fprintf (stderr, "cannot fill sigset: %s\n", strerror (errno));
+ fprintf (stderr, "cannot fill sigset: %m\n");
_exit (EXIT_FAILURE);
}
if (sigdelset (&sigset, SIGCHLD) < 0)
{
- fprintf (stderr, "cannot sigdelset(SIGCHLD): %s\n", strerror (errno));
+ fprintf (stderr, "cannot sigdelset(SIGCHLD): %m\n");
_exit (EXIT_FAILURE);
}
if (sigdelset (&sigset, SIGTERM) < 0)
{
- fprintf (stderr, "cannot sigdelset(SIGTERM): %s\n", strerror (errno));
+ fprintf (stderr, "cannot sigdelset(SIGTERM): %m\n");
_exit (EXIT_FAILURE);
}
if (sigprocmask (SIG_BLOCK, &sigset, &oldsigset) < 0)
{
- fprintf (stderr, "cannot block signals: %s\n", strerror (errno));
+ fprintf (stderr, "cannot block signals: %m\n");
_exit (EXIT_FAILURE);
}
@@ -717,33 +720,30 @@ reexec_userns_join (int pid_to_join, char *pause_pid_file_path)
if (prctl (PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0) < 0)
{
- fprintf (stderr, "cannot prctl(PR_SET_PDEATHSIG): %s\n", strerror (errno));
+ fprintf (stderr, "cannot prctl(PR_SET_PDEATHSIG): %m\n");
_exit (EXIT_FAILURE);
}
- join_namespace_or_die ("user", user_ns);
- join_namespace_or_die ("mnt", mnt_ns);
- close (user_ns);
- close (mnt_ns);
+ join_namespace_or_die ("user", userns_fd);
+ join_namespace_or_die ("mnt", mntns_fd);
if (syscall_setresgid (0, 0, 0) < 0)
{
- fprintf (stderr, "cannot setresgid: %s\n", strerror (errno));
+ fprintf (stderr, "cannot setresgid: %m\n");
_exit (EXIT_FAILURE);
}
if (syscall_setresuid (0, 0, 0) < 0)
{
- fprintf (stderr, "cannot setresuid: %s\n", strerror (errno));
+ fprintf (stderr, "cannot setresuid: %m\n");
_exit (EXIT_FAILURE);
}
if (chdir (cwd) < 0)
{
- fprintf (stderr, "cannot chdir to %s: %s\n", cwd, strerror (errno));
+ fprintf (stderr, "cannot chdir to %s: %m\n", cwd);
_exit (EXIT_FAILURE);
}
- free (cwd);
if (pause_pid_file_path && pause_pid_file_path[0] != '\0')
{
@@ -752,7 +752,7 @@ reexec_userns_join (int pid_to_join, char *pause_pid_file_path)
}
if (sigprocmask (SIG_SETMASK, &oldsigset, NULL) < 0)
{
- fprintf (stderr, "cannot block signals: %s\n", strerror (errno));
+ fprintf (stderr, "cannot block signals: %m\n");
_exit (EXIT_FAILURE);
}
@@ -784,7 +784,7 @@ static int
copy_file_to_fd (const char *file_to_read, int outfd)
{
char buf[512];
- int fd;
+ cleanup_close int fd = -1;
fd = open (file_to_read, O_RDONLY);
if (fd < 0)
@@ -796,10 +796,7 @@ copy_file_to_fd (const char *file_to_read, int outfd)
r = TEMP_FAILURE_RETRY (read (fd, buf, sizeof buf));
if (r < 0)
- {
- close (fd);
- return r;
- }
+ return r;
if (r == 0)
break;
@@ -808,43 +805,40 @@ copy_file_to_fd (const char *file_to_read, int outfd)
{
w = TEMP_FAILURE_RETRY (write (outfd, &buf[t], r - t));
if (w < 0)
- {
- close (fd);
- return w;
- }
+ return w;
t += w;
}
}
- close (fd);
return 0;
}
int
reexec_in_user_namespace (int ready, char *pause_pid_file_path, char *file_to_read, int outputfd)
{
+ cleanup_free char **argv = NULL;
+ cleanup_free char *argv0 = NULL;
+ cleanup_free char *cwd = NULL;
+ sigset_t sigset, oldsigset;
int ret;
pid_t pid;
char b;
- char **argv;
char uid[16];
char gid[16];
- char *cwd = getcwd (NULL, 0);
- sigset_t sigset, oldsigset;
+ cwd = getcwd (NULL, 0);
if (cwd == NULL)
{
- fprintf (stderr, "error getting current working directory: %s\n", strerror (errno));
+ fprintf (stderr, "error getting current working directory: %m\n");
_exit (EXIT_FAILURE);
}
-
sprintf (uid, "%d", geteuid ());
sprintf (gid, "%d", getegid ());
pid = syscall_clone (CLONE_NEWUSER|CLONE_NEWNS|SIGCHLD, NULL);
if (pid < 0)
{
- fprintf (stderr, "cannot clone: %s\n", strerror (errno));
+ fprintf (stderr, "cannot clone: %m\n");
check_proc_sys_userns_file (_max_user_namespaces);
check_proc_sys_userns_file (_unprivileged_user_namespaces);
}
@@ -872,32 +866,34 @@ reexec_in_user_namespace (int ready, char *pause_pid_file_path, char *file_to_re
if (sigfillset (&sigset) < 0)
{
- fprintf (stderr, "cannot fill sigset: %s\n", strerror (errno));
+ fprintf (stderr, "cannot fill sigset: %m\n");
_exit (EXIT_FAILURE);
}
if (sigdelset (&sigset, SIGCHLD) < 0)
{
- fprintf (stderr, "cannot sigdelset(SIGCHLD): %s\n", strerror (errno));
+ fprintf (stderr, "cannot sigdelset(SIGCHLD): %m\n");
_exit (EXIT_FAILURE);
}
if (sigdelset (&sigset, SIGTERM) < 0)
{
- fprintf (stderr, "cannot sigdelset(SIGTERM): %s\n", strerror (errno));
+ fprintf (stderr, "cannot sigdelset(SIGTERM): %m\n");
_exit (EXIT_FAILURE);
}
if (sigprocmask (SIG_BLOCK, &sigset, &oldsigset) < 0)
{
- fprintf (stderr, "cannot block signals: %s\n", strerror (errno));
+ fprintf (stderr, "cannot block signals: %m\n");
_exit (EXIT_FAILURE);
}
argv = get_cmd_line_args ();
if (argv == NULL)
{
- fprintf (stderr, "cannot read argv: %s\n", strerror (errno));
+ fprintf (stderr, "cannot read argv: %m\n");
_exit (EXIT_FAILURE);
}
+ argv0 = argv[0];
+
if (do_socket_activation)
{
char s[32];
@@ -916,7 +912,7 @@ reexec_in_user_namespace (int ready, char *pause_pid_file_path, char *file_to_re
ret = TEMP_FAILURE_RETRY (read (ready, &b, 1));
if (ret < 0)
{
- fprintf (stderr, "cannot read from sync pipe: %s\n", strerror (errno));
+ fprintf (stderr, "cannot read from sync pipe: %m\n");
_exit (EXIT_FAILURE);
}
if (ret != 1 || b != '0')
@@ -924,25 +920,24 @@ reexec_in_user_namespace (int ready, char *pause_pid_file_path, char *file_to_re
if (syscall_setresgid (0, 0, 0) < 0)
{
- fprintf (stderr, "cannot setresgid: %s\n", strerror (errno));
+ fprintf (stderr, "cannot setresgid: %m\n");
TEMP_FAILURE_RETRY (write (ready, "1", 1));
_exit (EXIT_FAILURE);
}
if (syscall_setresuid (0, 0, 0) < 0)
{
- fprintf (stderr, "cannot setresuid: %s\n", strerror (errno));
+ fprintf (stderr, "cannot setresuid: %m\n");
TEMP_FAILURE_RETRY (write (ready, "1", 1));
_exit (EXIT_FAILURE);
}
if (chdir (cwd) < 0)
{
- fprintf (stderr, "cannot chdir to %s: %s\n", cwd, strerror (errno));
+ fprintf (stderr, "cannot chdir to %s: %m\n", cwd);
TEMP_FAILURE_RETRY (write (ready, "1", 1));
_exit (EXIT_FAILURE);
}
- free (cwd);
if (pause_pid_file_path && pause_pid_file_path[0] != '\0')
{
@@ -956,14 +951,14 @@ reexec_in_user_namespace (int ready, char *pause_pid_file_path, char *file_to_re
ret = TEMP_FAILURE_RETRY (write (ready, "0", 1));
if (ret < 0)
{
- fprintf (stderr, "cannot write to ready pipe: %s\n", strerror (errno));
- _exit (EXIT_FAILURE);
+ fprintf (stderr, "cannot write to ready pipe: %m\n");
+ _exit (EXIT_FAILURE);
}
close (ready);
if (sigprocmask (SIG_SETMASK, &oldsigset, NULL) < 0)
{
- fprintf (stderr, "cannot block signals: %s\n", strerror (errno));
+ fprintf (stderr, "cannot block signals: %m\n");
_exit (EXIT_FAILURE);
}
diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go
index f90fef9e8..df5d2e8ff 100644
--- a/pkg/specgen/generate/container_create.go
+++ b/pkg/specgen/generate/container_create.go
@@ -3,17 +3,14 @@ package generate
import (
"context"
"fmt"
- "os"
"path/filepath"
"strings"
cdi "github.com/container-orchestrated-devices/container-device-interface/pkg"
"github.com/containers/common/libimage"
- "github.com/containers/common/pkg/config"
"github.com/containers/podman/v3/libpod"
"github.com/containers/podman/v3/pkg/specgen"
"github.com/containers/podman/v3/pkg/util"
- "github.com/containers/storage/types"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/selinux/go-selinux/label"
"github.com/pkg/errors"
@@ -163,15 +160,6 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener
}
options = append(options, opts...)
- var exitCommandArgs []string
-
- exitCommandArgs, err = CreateExitCommandArgs(rt.StorageConfig(), rtc, logrus.IsLevelEnabled(logrus.DebugLevel), s.Remove, false)
- if err != nil {
- return nil, nil, nil, err
- }
-
- options = append(options, libpod.WithExitCommand(exitCommandArgs))
-
if len(s.Aliases) > 0 {
options = append(options, libpod.WithNetworkAliases(s.Aliases))
}
@@ -500,54 +488,3 @@ func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen.
}
return options, nil
}
-
-func CreateExitCommandArgs(storageConfig types.StoreOptions, config *config.Config, syslog, rm, exec bool) ([]string, error) {
- // We need a cleanup process for containers in the current model.
- // But we can't assume that the caller is Podman - it could be another
- // user of the API.
- // As such, provide a way to specify a path to Podman, so we can
- // still invoke a cleanup process.
-
- podmanPath, err := os.Executable()
- if err != nil {
- return nil, err
- }
-
- command := []string{podmanPath,
- "--root", storageConfig.GraphRoot,
- "--runroot", storageConfig.RunRoot,
- "--log-level", logrus.GetLevel().String(),
- "--cgroup-manager", config.Engine.CgroupManager,
- "--tmpdir", config.Engine.TmpDir,
- "--cni-config-dir", config.Network.NetworkConfigDir,
- }
- if config.Engine.OCIRuntime != "" {
- command = append(command, []string{"--runtime", config.Engine.OCIRuntime}...)
- }
- if storageConfig.GraphDriverName != "" {
- command = append(command, []string{"--storage-driver", storageConfig.GraphDriverName}...)
- }
- for _, opt := range storageConfig.GraphDriverOptions {
- command = append(command, []string{"--storage-opt", opt}...)
- }
- if config.Engine.EventsLogger != "" {
- command = append(command, []string{"--events-backend", config.Engine.EventsLogger}...)
- }
-
- if syslog {
- command = append(command, "--syslog")
- }
- command = append(command, []string{"container", "cleanup"}...)
-
- if rm {
- command = append(command, "--rm")
- }
-
- // This has to be absolutely last, to ensure that the exec session ID
- // will be added after it by Libpod.
- if exec {
- command = append(command, "--exec")
- }
-
- return command, nil
-}
diff --git a/pkg/specgen/generate/pod_create.go b/pkg/specgen/generate/pod_create.go
index bfd81739a..72dd249e7 100644
--- a/pkg/specgen/generate/pod_create.go
+++ b/pkg/specgen/generate/pod_create.go
@@ -29,19 +29,16 @@ func buildPauseImage(rt *libpod.Runtime, rtConfig *config.Config) (string, error
return imageName, nil
}
- // NOTE: Having the pause binary in its own directory keeps the door
- // open for replacing the image building with using an overlay root FS.
- // The latter turned out to be complex and error prone (see #11956) but
- // we may be able to come up with a proper solution at a later point in
- // time.
- pausePath, err := rtConfig.FindHelperBinary("pause/pause", false)
+ // Also look into the path as some distributions install catatonit in
+ // /usr/bin.
+ catatonitPath, err := rtConfig.FindHelperBinary("catatonit", true)
if err != nil {
return "", fmt.Errorf("finding pause binary: %w", err)
}
buildContent := fmt.Sprintf(`FROM scratch
-COPY %s /pause
-ENTRYPOINT ["/pause"]`, pausePath)
+COPY %s /catatonit
+ENTRYPOINT ["/catatonit", "-P"]`, catatonitPath)
tmpF, err := ioutil.TempFile("", "pause.containerfile")
if err != nil {
diff --git a/pkg/specgenutil/util.go b/pkg/specgenutil/util.go
index 15676d086..b47082b7f 100644
--- a/pkg/specgenutil/util.go
+++ b/pkg/specgenutil/util.go
@@ -3,10 +3,13 @@ package specgenutil
import (
"io/ioutil"
"net"
+ "os"
"strconv"
"strings"
+ "github.com/containers/common/pkg/config"
"github.com/containers/podman/v3/libpod/network/types"
+ storageTypes "github.com/containers/storage/types"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
@@ -272,3 +275,54 @@ func parseAndValidatePort(port string) (uint16, error) {
}
return uint16(num), nil
}
+
+func CreateExitCommandArgs(storageConfig storageTypes.StoreOptions, config *config.Config, syslog, rm, exec bool) ([]string, error) {
+ // We need a cleanup process for containers in the current model.
+ // But we can't assume that the caller is Podman - it could be another
+ // user of the API.
+ // As such, provide a way to specify a path to Podman, so we can
+ // still invoke a cleanup process.
+
+ podmanPath, err := os.Executable()
+ if err != nil {
+ return nil, err
+ }
+
+ command := []string{podmanPath,
+ "--root", storageConfig.GraphRoot,
+ "--runroot", storageConfig.RunRoot,
+ "--log-level", logrus.GetLevel().String(),
+ "--cgroup-manager", config.Engine.CgroupManager,
+ "--tmpdir", config.Engine.TmpDir,
+ "--cni-config-dir", config.Network.NetworkConfigDir,
+ }
+ if config.Engine.OCIRuntime != "" {
+ command = append(command, []string{"--runtime", config.Engine.OCIRuntime}...)
+ }
+ if storageConfig.GraphDriverName != "" {
+ command = append(command, []string{"--storage-driver", storageConfig.GraphDriverName}...)
+ }
+ for _, opt := range storageConfig.GraphDriverOptions {
+ command = append(command, []string{"--storage-opt", opt}...)
+ }
+ if config.Engine.EventsLogger != "" {
+ command = append(command, []string{"--events-backend", config.Engine.EventsLogger}...)
+ }
+
+ if syslog {
+ command = append(command, "--syslog")
+ }
+ command = append(command, []string{"container", "cleanup"}...)
+
+ if rm {
+ command = append(command, "--rm")
+ }
+
+ // This has to be absolutely last, to ensure that the exec session ID
+ // will be added after it by Libpod.
+ if exec {
+ command = append(command, "--exec")
+ }
+
+ return command, nil
+}
diff --git a/pkg/specgenutil/volumes.go b/pkg/specgenutil/volumes.go
index 184bfadf8..8ff770f9c 100644
--- a/pkg/specgenutil/volumes.go
+++ b/pkg/specgenutil/volumes.go
@@ -355,6 +355,8 @@ func getBindMount(args []string) (spec.Mount, error) {
newMount.Options = append(newMount.Options, "U")
}
setOwnership = true
+ case "idmap":
+ newMount.Options = append(newMount.Options, "idmap")
case "consistency":
// Often used on MACs and mistakenly on Linux platforms.
// Since Docker ignores this option so shall we.
diff --git a/pkg/util/filters.go b/pkg/util/filters.go
index e252c1ddf..5af868873 100644
--- a/pkg/util/filters.go
+++ b/pkg/util/filters.go
@@ -4,6 +4,7 @@ import (
"encoding/json"
"fmt"
"net/http"
+ "regexp"
"strings"
"time"
@@ -94,6 +95,28 @@ func PrepareFilters(r *http.Request) (*map[string][]string, error) {
return &filterMap, nil
}
+func wildCardToRegexp(pattern string) string {
+ var result strings.Builder
+ for i, literal := range strings.Split(pattern, "*") {
+ // Replace * with .*
+ if i > 0 {
+ result.WriteString(".*")
+ }
+ // Quote any regular expression meta characters in the
+ // literal text.
+ result.WriteString(regexp.QuoteMeta(literal))
+ }
+ return result.String()
+}
+
+func matchPattern(pattern string, value string) bool {
+ if strings.Contains(pattern, "*") {
+ result, _ := regexp.MatchString(wildCardToRegexp(pattern), value)
+ return result
+ }
+ return false
+}
+
// MatchLabelFilters matches labels and returns true if they are valid
func MatchLabelFilters(filterValues []string, labels map[string]string) bool {
outer:
@@ -106,7 +129,7 @@ outer:
filterValue = ""
}
for labelKey, labelValue := range labels {
- if labelKey == filterKey && (filterValue == "" || labelValue == filterValue) {
+ if ((labelKey == filterKey) || matchPattern(filterKey, labelKey)) && (filterValue == "" || labelValue == filterValue) {
continue outer
}
}
diff --git a/pkg/util/mountOpts.go b/pkg/util/mountOpts.go
index f13dc94ec..959763dba 100644
--- a/pkg/util/mountOpts.go
+++ b/pkg/util/mountOpts.go
@@ -33,6 +33,7 @@ func ProcessOptions(options []string, isTmpfs bool, sourcePath string) ([]string
// Some options have parameters - size, mode
splitOpt := strings.SplitN(opt, "=", 2)
switch splitOpt[0] {
+ case "idmap":
case "O":
if len(options) > 1 {
return nil, errors.Wrapf(ErrDupeMntOption, "'O' option can not be used with other options")