diff --git a/libpod/container_internal_common.go b/libpod/container_internal_common.go index acaa76ef3ae..d40d65a914c 100644 --- a/libpod/container_internal_common.go +++ b/libpod/container_internal_common.go @@ -1569,8 +1569,18 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti // Let's try to stat() CRIU's inventory file. If it does not exist, it makes // no sense to try a restore. This is a minimal check if a checkpoint exists. - if err := fileutils.Exists(filepath.Join(c.CheckpointPath(), "inventory.img")); errors.Is(err, fs.ErrNotExist) { - return nil, 0, fmt.Errorf("a complete checkpoint for this container cannot be found, cannot restore: %w", err) + // For gVisor, the checkpoint image is called "checkpoint.img". + criuInventoryPath := filepath.Join(c.CheckpointPath(), "inventory.img") + gvisorCheckpointPath := filepath.Join(c.CheckpointPath(), "checkpoint.img") + + if err := fileutils.Exists(criuInventoryPath); errors.Is(err, fs.ErrNotExist) { + if err2 := fileutils.Exists(gvisorCheckpointPath); errors.Is(err2, fs.ErrNotExist) { + return nil, 0, fmt.Errorf("a complete checkpoint for this container cannot be found (checked %q and %q): %w", criuInventoryPath, gvisorCheckpointPath, err) + } else if err2 != nil { + return nil, 0, fmt.Errorf("error checking checkpoint file %q: %w", gvisorCheckpointPath, err2) + } + } else if err != nil { + return nil, 0, fmt.Errorf("error checking inventory file %q: %w", criuInventoryPath, err) } if err := crutils.CRCreateFileWithLabel(c.bundlePath(), "restore.log", c.MountLabel()); err != nil { diff --git a/pkg/checkpoint/crutils/checkpoint_restore_utils.go b/pkg/checkpoint/crutils/checkpoint_restore_utils.go index 1709429bad8..1c24e291db7 100644 --- a/pkg/checkpoint/crutils/checkpoint_restore_utils.go +++ b/pkg/checkpoint/crutils/checkpoint_restore_utils.go @@ -216,9 +216,22 @@ func CRRuntimeSupportsCheckpointRestore(runtimePath string) bool { if err := cmd.Start(); err != nil { return false } - if err := cmd.Wait(); err == nil { + + err := cmd.Wait() + if err == nil { + // Exited with status 0 means definitely supported. return true } + + if exitErr, ok := err.(*exec.ExitError); ok { + status := exitErr.ExitCode() + // "runsc checkpoint --help" exits with 128 (subcommands.ExitUsageError) + // and 127 is used for "command not found". + if status == 128 { + return true + } + } + return false }