diff options
Diffstat (limited to 'libpod')
26 files changed, 475 insertions, 439 deletions
diff --git a/libpod/container.go b/libpod/container.go index cfffd8ea1..a4eb33c49 100644 --- a/libpod/container.go +++ b/libpod/container.go @@ -3,7 +3,7 @@ package libpod import ( "bytes" "fmt" - "io/ioutil" + "io" "net" "os" "strings" @@ -351,7 +351,7 @@ func (c *Container) specFromState() (*spec.Spec, error) { if f, err := os.Open(c.state.ConfigPath); err == nil { returnSpec = new(spec.Spec) - content, err := ioutil.ReadAll(f) + content, err := io.ReadAll(f) if err != nil { return nil, fmt.Errorf("reading container config: %w", err) } @@ -990,7 +990,7 @@ func (c *Container) cGroupPath() (string, error) { // the lookup. // See #10602 for more details. procPath := fmt.Sprintf("/proc/%d/cgroup", c.state.PID) - lines, err := ioutil.ReadFile(procPath) + lines, err := os.ReadFile(procPath) if err != nil { // If the file doesn't exist, it means the container could have been terminated // so report it. diff --git a/libpod/container_api.go b/libpod/container_api.go index dd47b4d12..be0ca0128 100644 --- a/libpod/container_api.go +++ b/libpod/container_api.go @@ -5,7 +5,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "net/http" "os" "sync" @@ -479,7 +478,7 @@ func (c *Container) AddArtifact(name string, data []byte) error { return define.ErrCtrRemoved } - return ioutil.WriteFile(c.getArtifactPath(name), data, 0o740) + return os.WriteFile(c.getArtifactPath(name), data, 0o740) } // GetArtifact reads the specified artifact file from the container @@ -488,7 +487,7 @@ func (c *Container) GetArtifact(name string) ([]byte, error) { return nil, define.ErrCtrRemoved } - return ioutil.ReadFile(c.getArtifactPath(name)) + return os.ReadFile(c.getArtifactPath(name)) } // RemoveArtifact deletes the specified artifacts file diff --git a/libpod/container_copy_common.go b/libpod/container_copy_common.go new file mode 100644 index 000000000..d07b4c692 --- /dev/null +++ b/libpod/container_copy_common.go @@ -0,0 +1,213 @@ +//go:build linux || freebsd +// +build linux freebsd + +package libpod + +import ( + "errors" + "io" + "path/filepath" + "strings" + + buildahCopiah "github.com/containers/buildah/copier" + "github.com/containers/buildah/pkg/chrootuser" + "github.com/containers/buildah/util" + "github.com/containers/podman/v4/libpod/define" + "github.com/containers/podman/v4/pkg/rootless" + "github.com/containers/storage/pkg/archive" + "github.com/containers/storage/pkg/idtools" + "github.com/opencontainers/runtime-spec/specs-go" + "github.com/sirupsen/logrus" +) + +func (c *Container) copyFromArchive(path string, chown, noOverwriteDirNonDir bool, rename map[string]string, reader io.Reader) (func() error, error) { + var ( + mountPoint string + resolvedRoot string + resolvedPath string + unmount func() + err error + ) + + // Make sure that "/" copies the *contents* of the mount point and not + // the directory. + if path == "/" { + path = "/." + } + + // Optimization: only mount if the container is not already. + if c.state.Mounted { + mountPoint = c.state.Mountpoint + unmount = func() {} + } else { + // NOTE: make sure to unmount in error paths. + mountPoint, err = c.mount() + if err != nil { + return nil, err + } + unmount = func() { + if err := c.unmount(false); err != nil { + logrus.Errorf("Failed to unmount container: %v", err) + } + } + } + + resolvedRoot, resolvedPath, err = c.resolveCopyTarget(mountPoint, path) + if err != nil { + unmount() + return nil, err + } + + var idPair *idtools.IDPair + if chown { + // Make sure we chown the files to the container's main user and group ID. + user, err := getContainerUser(c, mountPoint) + if err != nil { + unmount() + return nil, err + } + idPair = &idtools.IDPair{UID: int(user.UID), GID: int(user.GID)} + } + + decompressed, err := archive.DecompressStream(reader) + if err != nil { + unmount() + return nil, err + } + + logrus.Debugf("Container copy *to* %q (resolved: %q) on container %q (ID: %s)", path, resolvedPath, c.Name(), c.ID()) + + return func() error { + defer unmount() + defer decompressed.Close() + putOptions := buildahCopiah.PutOptions{ + UIDMap: c.config.IDMappings.UIDMap, + GIDMap: c.config.IDMappings.GIDMap, + ChownDirs: idPair, + ChownFiles: idPair, + NoOverwriteDirNonDir: noOverwriteDirNonDir, + NoOverwriteNonDirDir: noOverwriteDirNonDir, + Rename: rename, + } + + return c.joinMountAndExec( + func() error { + return buildahCopiah.Put(resolvedRoot, resolvedPath, putOptions, decompressed) + }, + ) + }, nil +} + +func (c *Container) copyToArchive(path string, writer io.Writer) (func() error, error) { + var ( + mountPoint string + unmount func() + err error + ) + + // Optimization: only mount if the container is not already. + if c.state.Mounted { + mountPoint = c.state.Mountpoint + unmount = func() {} + } else { + // NOTE: make sure to unmount in error paths. + mountPoint, err = c.mount() + if err != nil { + return nil, err + } + unmount = func() { + if err := c.unmount(false); err != nil { + logrus.Errorf("Failed to unmount container: %v", err) + } + } + } + + statInfo, resolvedRoot, resolvedPath, err := c.stat(mountPoint, path) + if err != nil { + unmount() + return nil, err + } + + // We optimistically chown to the host user. In case of a hypothetical + // container-to-container copy, the reading side will chown back to the + // container user. + user, err := getContainerUser(c, mountPoint) + if err != nil { + unmount() + return nil, err + } + hostUID, hostGID, err := util.GetHostIDs( + idtoolsToRuntimeSpec(c.config.IDMappings.UIDMap), + idtoolsToRuntimeSpec(c.config.IDMappings.GIDMap), + user.UID, + user.GID, + ) + if err != nil { + unmount() + return nil, err + } + idPair := idtools.IDPair{UID: int(hostUID), GID: int(hostGID)} + + logrus.Debugf("Container copy *from* %q (resolved: %q) on container %q (ID: %s)", path, resolvedPath, c.Name(), c.ID()) + + return func() error { + defer unmount() + getOptions := buildahCopiah.GetOptions{ + // Unless the specified points to ".", we want to copy the base directory. + KeepDirectoryNames: statInfo.IsDir && filepath.Base(path) != ".", + UIDMap: c.config.IDMappings.UIDMap, + GIDMap: c.config.IDMappings.GIDMap, + ChownDirs: &idPair, + ChownFiles: &idPair, + Excludes: []string{"dev", "proc", "sys"}, + // Ignore EPERMs when copying from rootless containers + // since we cannot read TTY devices. Those are owned + // by the host's root and hence "nobody" inside the + // container's user namespace. + IgnoreUnreadable: rootless.IsRootless() && c.state.State == define.ContainerStateRunning, + } + return c.joinMountAndExec( + func() error { + return buildahCopiah.Get(resolvedRoot, "", getOptions, []string{resolvedPath}, writer) + }, + ) + }, nil +} + +// getContainerUser returns the specs.User and ID mappings of the container. +func getContainerUser(container *Container, mountPoint string) (specs.User, error) { + userspec := container.config.User + + uid, gid, _, err := chrootuser.GetUser(mountPoint, userspec) + u := specs.User{ + UID: uid, + GID: gid, + Username: userspec, + } + + if !strings.Contains(userspec, ":") { + groups, err2 := chrootuser.GetAdditionalGroupsForUser(mountPoint, uint64(u.UID)) + if err2 != nil { + if !errors.Is(err2, chrootuser.ErrNoSuchUser) && err == nil { + err = err2 + } + } else { + u.AdditionalGids = groups + } + } + + return u, err +} + +// idtoolsToRuntimeSpec converts idtools ID mapping to the one of the runtime spec. +func idtoolsToRuntimeSpec(idMaps []idtools.IDMap) (convertedIDMap []specs.LinuxIDMapping) { + for _, idmap := range idMaps { + tempIDMap := specs.LinuxIDMapping{ + ContainerID: uint32(idmap.ContainerID), + HostID: uint32(idmap.HostID), + Size: uint32(idmap.Size), + } + convertedIDMap = append(convertedIDMap, tempIDMap) + } + return convertedIDMap +} diff --git a/libpod/container_copy_freebsd.go b/libpod/container_copy_freebsd.go new file mode 100644 index 000000000..218f3917f --- /dev/null +++ b/libpod/container_copy_freebsd.go @@ -0,0 +1,13 @@ +package libpod + +// On FreeBSD, the container's mounts are in the global mount +// namespace so we can just execute the function directly. +func (c *Container) joinMountAndExec(f func() error) error { + return f() +} + +// Similarly, we can just use resolvePath for both running and stopped +// containers. +func (c *Container) resolveCopyTarget(mountPoint string, containerPath string) (string, string, error) { + return c.resolvePath(mountPoint, containerPath) +} diff --git a/libpod/container_copy_linux.go b/libpod/container_copy_linux.go index 557fead1e..3b029f08f 100644 --- a/libpod/container_copy_linux.go +++ b/libpod/container_copy_linux.go @@ -1,226 +1,14 @@ -//go:build linux -// +build linux - package libpod import ( - "errors" "fmt" - "io" "os" - "path/filepath" "runtime" - "strings" - buildahCopiah "github.com/containers/buildah/copier" - "github.com/containers/buildah/pkg/chrootuser" - "github.com/containers/buildah/util" "github.com/containers/podman/v4/libpod/define" - "github.com/containers/podman/v4/pkg/rootless" - "github.com/containers/storage/pkg/archive" - "github.com/containers/storage/pkg/idtools" - "github.com/opencontainers/runtime-spec/specs-go" - "github.com/sirupsen/logrus" "golang.org/x/sys/unix" ) -func (c *Container) copyFromArchive(path string, chown, noOverwriteDirNonDir bool, rename map[string]string, reader io.Reader) (func() error, error) { - var ( - mountPoint string - resolvedRoot string - resolvedPath string - unmount func() - err error - ) - - // Make sure that "/" copies the *contents* of the mount point and not - // the directory. - if path == "/" { - path = "/." - } - - // Optimization: only mount if the container is not already. - if c.state.Mounted { - mountPoint = c.state.Mountpoint - unmount = func() {} - } else { - // NOTE: make sure to unmount in error paths. - mountPoint, err = c.mount() - if err != nil { - return nil, err - } - unmount = func() { - if err := c.unmount(false); err != nil { - logrus.Errorf("Failed to unmount container: %v", err) - } - } - } - - if c.state.State == define.ContainerStateRunning { - resolvedRoot = "/" - resolvedPath = c.pathAbs(path) - } else { - resolvedRoot, resolvedPath, err = c.resolvePath(mountPoint, path) - if err != nil { - unmount() - return nil, err - } - } - - var idPair *idtools.IDPair - if chown { - // Make sure we chown the files to the container's main user and group ID. - user, err := getContainerUser(c, mountPoint) - if err != nil { - unmount() - return nil, err - } - idPair = &idtools.IDPair{UID: int(user.UID), GID: int(user.GID)} - } - - decompressed, err := archive.DecompressStream(reader) - if err != nil { - unmount() - return nil, err - } - - logrus.Debugf("Container copy *to* %q (resolved: %q) on container %q (ID: %s)", path, resolvedPath, c.Name(), c.ID()) - - return func() error { - defer unmount() - defer decompressed.Close() - putOptions := buildahCopiah.PutOptions{ - UIDMap: c.config.IDMappings.UIDMap, - GIDMap: c.config.IDMappings.GIDMap, - ChownDirs: idPair, - ChownFiles: idPair, - NoOverwriteDirNonDir: noOverwriteDirNonDir, - NoOverwriteNonDirDir: noOverwriteDirNonDir, - Rename: rename, - } - - return c.joinMountAndExec( - func() error { - return buildahCopiah.Put(resolvedRoot, resolvedPath, putOptions, decompressed) - }, - ) - }, nil -} - -func (c *Container) copyToArchive(path string, writer io.Writer) (func() error, error) { - var ( - mountPoint string - unmount func() - err error - ) - - // Optimization: only mount if the container is not already. - if c.state.Mounted { - mountPoint = c.state.Mountpoint - unmount = func() {} - } else { - // NOTE: make sure to unmount in error paths. - mountPoint, err = c.mount() - if err != nil { - return nil, err - } - unmount = func() { - if err := c.unmount(false); err != nil { - logrus.Errorf("Failed to unmount container: %v", err) - } - } - } - - statInfo, resolvedRoot, resolvedPath, err := c.stat(mountPoint, path) - if err != nil { - unmount() - return nil, err - } - - // We optimistically chown to the host user. In case of a hypothetical - // container-to-container copy, the reading side will chown back to the - // container user. - user, err := getContainerUser(c, mountPoint) - if err != nil { - unmount() - return nil, err - } - hostUID, hostGID, err := util.GetHostIDs( - idtoolsToRuntimeSpec(c.config.IDMappings.UIDMap), - idtoolsToRuntimeSpec(c.config.IDMappings.GIDMap), - user.UID, - user.GID, - ) - if err != nil { - unmount() - return nil, err - } - idPair := idtools.IDPair{UID: int(hostUID), GID: int(hostGID)} - - logrus.Debugf("Container copy *from* %q (resolved: %q) on container %q (ID: %s)", path, resolvedPath, c.Name(), c.ID()) - - return func() error { - defer unmount() - getOptions := buildahCopiah.GetOptions{ - // Unless the specified points to ".", we want to copy the base directory. - KeepDirectoryNames: statInfo.IsDir && filepath.Base(path) != ".", - UIDMap: c.config.IDMappings.UIDMap, - GIDMap: c.config.IDMappings.GIDMap, - ChownDirs: &idPair, - ChownFiles: &idPair, - Excludes: []string{"dev", "proc", "sys"}, - // Ignore EPERMs when copying from rootless containers - // since we cannot read TTY devices. Those are owned - // by the host's root and hence "nobody" inside the - // container's user namespace. - IgnoreUnreadable: rootless.IsRootless() && c.state.State == define.ContainerStateRunning, - } - return c.joinMountAndExec( - func() error { - return buildahCopiah.Get(resolvedRoot, "", getOptions, []string{resolvedPath}, writer) - }, - ) - }, nil -} - -// getContainerUser returns the specs.User and ID mappings of the container. -func getContainerUser(container *Container, mountPoint string) (specs.User, error) { - userspec := container.config.User - - uid, gid, _, err := chrootuser.GetUser(mountPoint, userspec) - u := specs.User{ - UID: uid, - GID: gid, - Username: userspec, - } - - if !strings.Contains(userspec, ":") { - groups, err2 := chrootuser.GetAdditionalGroupsForUser(mountPoint, uint64(u.UID)) - if err2 != nil { - if !errors.Is(err2, chrootuser.ErrNoSuchUser) && err == nil { - err = err2 - } - } else { - u.AdditionalGids = groups - } - } - - return u, err -} - -// idtoolsToRuntimeSpec converts idtools ID mapping to the one of the runtime spec. -func idtoolsToRuntimeSpec(idMaps []idtools.IDMap) (convertedIDMap []specs.LinuxIDMapping) { - for _, idmap := range idMaps { - tempIDMap := specs.LinuxIDMapping{ - ContainerID: uint32(idmap.ContainerID), - HostID: uint32(idmap.HostID), - Size: uint32(idmap.Size), - } - convertedIDMap = append(convertedIDMap, tempIDMap) - } - return convertedIDMap -} - // joinMountAndExec executes the specified function `f` inside the container's // mount and PID namespace. That allows for having the exact view on the // container's file system. @@ -288,3 +76,13 @@ func (c *Container) joinMountAndExec(f func() error) error { }() return <-errChan } + +func (c *Container) resolveCopyTarget(mountPoint string, containerPath string) (string, string, error) { + // If the container is running, we will execute the copy + // inside the container's mount namespace so we return a path + // relative to the container's root. + if c.state.State == define.ContainerStateRunning { + return "/", c.pathAbs(containerPath), nil + } + return c.resolvePath(mountPoint, containerPath) +} diff --git a/libpod/container_copy_unsupported.go b/libpod/container_copy_unsupported.go index 62937279a..703b0a74e 100644 --- a/libpod/container_copy_unsupported.go +++ b/libpod/container_copy_unsupported.go @@ -1,5 +1,5 @@ -//go:build !linux -// +build !linux +//go:build !linux && !freebsd +// +build !linux,!freebsd package libpod diff --git a/libpod/container_exec.go b/libpod/container_exec.go index 3a2cba52f..7896d1932 100644 --- a/libpod/container_exec.go +++ b/libpod/container_exec.go @@ -4,7 +4,6 @@ import ( "context" "errors" "fmt" - "io/ioutil" "net/http" "os" "path/filepath" @@ -928,7 +927,7 @@ func (c *Container) readExecExitCode(sessionID string) (int, error) { if err != nil { return -1, err } - ec, err := ioutil.ReadFile(exitFile) + ec, err := os.ReadFile(exitFile) if err != nil { return -1, err } diff --git a/libpod/container_internal.go b/libpod/container_internal.go index 994243805..9bf93412d 100644 --- a/libpod/container_internal.go +++ b/libpod/container_internal.go @@ -6,7 +6,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "os" "path/filepath" "strconv" @@ -201,7 +200,7 @@ func (c *Container) waitForExitFileAndSync() error { // This assumes the exit file already exists. func (c *Container) handleExitFile(exitFile string, fi os.FileInfo) error { c.state.FinishedTime = ctime.Created(fi) - statusCodeStr, err := ioutil.ReadFile(exitFile) + statusCodeStr, err := os.ReadFile(exitFile) if err != nil { return fmt.Errorf("failed to read exit file for container %s: %w", c.ID(), err) } @@ -2089,7 +2088,7 @@ func (c *Container) saveSpec(spec *spec.Spec) error { if err != nil { return fmt.Errorf("exporting runtime spec for container %s to JSON: %w", c.ID(), err) } - if err := ioutil.WriteFile(jsonPath, fileJSON, 0644); err != nil { + if err := os.WriteFile(jsonPath, fileJSON, 0644); err != nil { return fmt.Errorf("writing runtime spec JSON for container %s to disk: %w", c.ID(), err) } @@ -2343,7 +2342,7 @@ func (c *Container) extractSecretToCtrStorage(secr *ContainerSecret) error { if err != nil { return fmt.Errorf("unable to extract secret: %w", err) } - err = ioutil.WriteFile(secretFile, data, 0644) + err = os.WriteFile(secretFile, data, 0644) if err != nil { return fmt.Errorf("unable to create %s: %w", secretFile, err) } diff --git a/libpod/container_internal_common.go b/libpod/container_internal_common.go index 9c4a3bb67..29107d4b6 100644 --- a/libpod/container_internal_common.go +++ b/libpod/container_internal_common.go @@ -8,7 +8,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "math" "os" "os/user" @@ -110,7 +109,11 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) { // If the flag to mount all devices is set for a privileged container, add // all the devices from the host's machine into the container if c.config.MountAllDevices { - if err := util.AddPrivilegedDevices(&g); err != nil { + systemdMode := false + if c.config.Systemd != nil { + systemdMode = *c.config.Systemd + } + if err := util.AddPrivilegedDevices(&g, systemdMode); err != nil { return nil, err } } @@ -788,7 +791,7 @@ func (c *Container) createCheckpointImage(ctx context.Context, options Container } // Export checkpoint into temporary tar file - tmpDir, err := ioutil.TempDir("", "checkpoint_image_") + tmpDir, err := os.MkdirTemp("", "checkpoint_image_") if err != nil { return err } @@ -2442,7 +2445,7 @@ func (c *Container) generatePasswdAndGroup() (string, string, error) { if err != nil { return "", "", fmt.Errorf("creating path to container %s /etc/passwd: %w", c.ID(), err) } - orig, err := ioutil.ReadFile(originPasswdFile) + orig, err := os.ReadFile(originPasswdFile) if err != nil && !os.IsNotExist(err) { return "", "", err } @@ -2488,7 +2491,7 @@ func (c *Container) generatePasswdAndGroup() (string, string, error) { if err != nil { return "", "", fmt.Errorf("creating path to container %s /etc/group: %w", c.ID(), err) } - orig, err := ioutil.ReadFile(originGroupFile) + orig, err := os.ReadFile(originGroupFile) if err != nil && !os.IsNotExist(err) { return "", "", err } @@ -2659,7 +2662,7 @@ func (c *Container) fixVolumePermissions(v *ContainerNamedVolume) error { return nil } -func (c *Container) relabel(src, mountLabel string, recurse bool) error { +func (c *Container) relabel(src, mountLabel string, shared bool) error { if !selinux.GetEnabled() || mountLabel == "" { return nil } @@ -2674,7 +2677,7 @@ func (c *Container) relabel(src, mountLabel string, recurse bool) error { return nil } } - return label.Relabel(src, mountLabel, recurse) + return label.Relabel(src, mountLabel, shared) } func (c *Container) ChangeHostPathOwnership(src string, recurse bool, uid, gid int) error { diff --git a/libpod/container_internal_test.go b/libpod/container_internal_test.go index 1b4e62e91..46a2da544 100644 --- a/libpod/container_internal_test.go +++ b/libpod/container_internal_test.go @@ -3,7 +3,7 @@ package libpod import ( "context" "fmt" - "io/ioutil" + "os" "path/filepath" "runtime" "testing" @@ -60,7 +60,7 @@ func TestPostDeleteHooks(t *testing.T) { for _, p := range []string{statePath, copyPath} { path := p t.Run(path, func(t *testing.T) { - content, err := ioutil.ReadFile(path) + content, err := os.ReadFile(path) if err != nil { t.Fatal(err) } diff --git a/libpod/container_stat_common.go b/libpod/container_stat_common.go new file mode 100644 index 000000000..e59a52ede --- /dev/null +++ b/libpod/container_stat_common.go @@ -0,0 +1,155 @@ +//go:build linux || freebsd +// +build linux freebsd + +package libpod + +import ( + "errors" + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/containers/buildah/copier" + "github.com/containers/podman/v4/libpod/define" + "github.com/containers/podman/v4/pkg/copy" +) + +// statOnHost stats the specified path *on the host*. It returns the file info +// along with the resolved root and the resolved path. Both paths are absolute +// to the host's root. Note that the paths may resolved outside the +// container's mount point (e.g., to a volume or bind mount). +func (c *Container) statOnHost(mountPoint string, containerPath string) (*copier.StatForItem, string, string, error) { + // Now resolve the container's path. It may hit a volume, it may hit a + // bind mount, it may be relative. + resolvedRoot, resolvedPath, err := c.resolvePath(mountPoint, containerPath) + if err != nil { + return nil, "", "", err + } + + statInfo, err := secureStat(resolvedRoot, resolvedPath) + return statInfo, resolvedRoot, resolvedPath, err +} + +func (c *Container) stat(containerMountPoint string, containerPath string) (*define.FileInfo, string, string, error) { + var ( + resolvedRoot string + resolvedPath string + absContainerPath string + statInfo *copier.StatForItem + statErr error + ) + + // Make sure that "/" copies the *contents* of the mount point and not + // the directory. + if containerPath == "/" { + containerPath = "/." + } + + // Wildcards are not allowed. + // TODO: it's now technically possible wildcards. + // We may consider enabling support in the future. + if strings.Contains(containerPath, "*") { + return nil, "", "", copy.ErrENOENT + } + + statInfo, resolvedRoot, resolvedPath, statErr = c.statInContainer(containerMountPoint, containerPath) + if statErr != nil { + if statInfo == nil { + return nil, "", "", statErr + } + // Not all errors from secureStat map to ErrNotExist, so we + // have to look into the error string. Turning it into an + // ENOENT let's the API handlers return the correct status code + // which is crucial for the remote client. + if os.IsNotExist(statErr) || strings.Contains(statErr.Error(), "o such file or directory") { + statErr = copy.ErrENOENT + } + } + + switch { + case statInfo.IsSymlink: + // Symlinks are already evaluated and always relative to the + // container's mount point. + absContainerPath = statInfo.ImmediateTarget + case strings.HasPrefix(resolvedPath, containerMountPoint): + // If the path is on the container's mount point, strip it off. + absContainerPath = strings.TrimPrefix(resolvedPath, containerMountPoint) + absContainerPath = filepath.Join("/", absContainerPath) + default: + // No symlink and not on the container's mount point, so let's + // move it back to the original input. It must have evaluated + // to a volume or bind mount but we cannot return host paths. + absContainerPath = containerPath + } + + // Preserve the base path as specified by the user. The `filepath` + // packages likes to remove trailing slashes and dots that are crucial + // to the copy logic. + absContainerPath = copy.PreserveBasePath(containerPath, absContainerPath) + resolvedPath = copy.PreserveBasePath(containerPath, resolvedPath) + + info := &define.FileInfo{ + IsDir: statInfo.IsDir, + Name: filepath.Base(absContainerPath), + Size: statInfo.Size, + Mode: statInfo.Mode, + ModTime: statInfo.ModTime, + LinkTarget: absContainerPath, + } + + return info, resolvedRoot, resolvedPath, statErr +} + +// secureStat extracts file info for path in a chroot'ed environment in root. +func secureStat(root string, path string) (*copier.StatForItem, error) { + var glob string + var err error + + // If root and path are equal, then dir must be empty and the glob must + // be ".". + if filepath.Clean(root) == filepath.Clean(path) { + glob = "." + } else { + glob, err = filepath.Rel(root, path) + if err != nil { + return nil, err + } + } + + globStats, err := copier.Stat(root, "", copier.StatOptions{}, []string{glob}) + if err != nil { + return nil, err + } + + if len(globStats) != 1 { + return nil, fmt.Errorf("internal error: secureStat: expected 1 item but got %d", len(globStats)) + } + if len(globStats) != 1 { + return nil, fmt.Errorf("internal error: secureStat: expected 1 result but got %d", len(globStats[0].Results)) + } + + // NOTE: the key in the map differ from `glob` when hitting symlink. + // Hence, we just take the first (and only) key/value pair. + for _, stat := range globStats[0].Results { + var statErr error + if stat.Error != "" { + statErr = errors.New(stat.Error) + } + // If necessary evaluate the symlink + if stat.IsSymlink { + target, err := copier.Eval(root, path, copier.EvalOptions{}) + if err != nil { + return nil, fmt.Errorf("evaluating symlink in container: %w", err) + } + // Need to make sure the symlink is relative to the root! + target = strings.TrimPrefix(target, root) + target = filepath.Join("/", target) + stat.ImmediateTarget = target + } + return stat, statErr + } + + // Nothing found! + return nil, copy.ErrENOENT +} diff --git a/libpod/container_stat_freebsd.go b/libpod/container_stat_freebsd.go new file mode 100644 index 000000000..d1e0db348 --- /dev/null +++ b/libpod/container_stat_freebsd.go @@ -0,0 +1,13 @@ +package libpod + +import ( + "github.com/containers/buildah/copier" +) + +// On FreeBSD, jails use the global mount namespace, filtered to only +// the mounts the jail should see. This means that we can use +// statOnHost whether the container is running or not. +// container is running +func (c *Container) statInContainer(mountPoint string, containerPath string) (*copier.StatForItem, string, string, error) { + return c.statOnHost(mountPoint, containerPath) +} diff --git a/libpod/container_stat_linux.go b/libpod/container_stat_linux.go index dc3a524f5..5e5ef3c1a 100644 --- a/libpod/container_stat_linux.go +++ b/libpod/container_stat_linux.go @@ -1,18 +1,8 @@ -//go:build linux -// +build linux - package libpod import ( - "errors" - "fmt" - "os" - "path/filepath" - "strings" - "github.com/containers/buildah/copier" "github.com/containers/podman/v4/libpod/define" - "github.com/containers/podman/v4/pkg/copy" ) // statInsideMount stats the specified path *inside* the container's mount and PID @@ -34,150 +24,15 @@ func (c *Container) statInsideMount(containerPath string) (*copier.StatForItem, return statInfo, resolvedRoot, resolvedPath, err } -// statOnHost stats the specified path *on the host*. It returns the file info -// along with the resolved root and the resolved path. Both paths are absolute -// to the host's root. Note that the paths may resolved outside the -// container's mount point (e.g., to a volume or bind mount). -func (c *Container) statOnHost(mountPoint string, containerPath string) (*copier.StatForItem, string, string, error) { - // Now resolve the container's path. It may hit a volume, it may hit a - // bind mount, it may be relative. - resolvedRoot, resolvedPath, err := c.resolvePath(mountPoint, containerPath) - if err != nil { - return nil, "", "", err - } - - statInfo, err := secureStat(resolvedRoot, resolvedPath) - return statInfo, resolvedRoot, resolvedPath, err -} - -func (c *Container) stat(containerMountPoint string, containerPath string) (*define.FileInfo, string, string, error) { - var ( - resolvedRoot string - resolvedPath string - absContainerPath string - statInfo *copier.StatForItem - statErr error - ) - - // Make sure that "/" copies the *contents* of the mount point and not - // the directory. - if containerPath == "/" { - containerPath = "/." - } - - // Wildcards are not allowed. - // TODO: it's now technically possible wildcards. - // We may consider enabling support in the future. - if strings.Contains(containerPath, "*") { - return nil, "", "", copy.ErrENOENT - } - +// Calls either statOnHost or statInsideMount depending on whether the +// container is running +func (c *Container) statInContainer(mountPoint string, containerPath string) (*copier.StatForItem, string, string, error) { if c.state.State == define.ContainerStateRunning { // If the container is running, we need to join it's mount namespace // and stat there. - statInfo, resolvedRoot, resolvedPath, statErr = c.statInsideMount(containerPath) - } else { - // If the container is NOT running, we need to resolve the path - // on the host. - statInfo, resolvedRoot, resolvedPath, statErr = c.statOnHost(containerMountPoint, containerPath) - } - - if statErr != nil { - if statInfo == nil { - return nil, "", "", statErr - } - // Not all errors from secureStat map to ErrNotExist, so we - // have to look into the error string. Turning it into an - // ENOENT let's the API handlers return the correct status code - // which is crucial for the remote client. - if os.IsNotExist(statErr) || strings.Contains(statErr.Error(), "o such file or directory") { - statErr = copy.ErrENOENT - } - } - - switch { - case statInfo.IsSymlink: - // Symlinks are already evaluated and always relative to the - // container's mount point. - absContainerPath = statInfo.ImmediateTarget - case strings.HasPrefix(resolvedPath, containerMountPoint): - // If the path is on the container's mount point, strip it off. - absContainerPath = strings.TrimPrefix(resolvedPath, containerMountPoint) - absContainerPath = filepath.Join("/", absContainerPath) - default: - // No symlink and not on the container's mount point, so let's - // move it back to the original input. It must have evaluated - // to a volume or bind mount but we cannot return host paths. - absContainerPath = containerPath + return c.statInsideMount(containerPath) } - - // Preserve the base path as specified by the user. The `filepath` - // packages likes to remove trailing slashes and dots that are crucial - // to the copy logic. - absContainerPath = copy.PreserveBasePath(containerPath, absContainerPath) - resolvedPath = copy.PreserveBasePath(containerPath, resolvedPath) - - info := &define.FileInfo{ - IsDir: statInfo.IsDir, - Name: filepath.Base(absContainerPath), - Size: statInfo.Size, - Mode: statInfo.Mode, - ModTime: statInfo.ModTime, - LinkTarget: absContainerPath, - } - - return info, resolvedRoot, resolvedPath, statErr -} - -// secureStat extracts file info for path in a chroot'ed environment in root. -func secureStat(root string, path string) (*copier.StatForItem, error) { - var glob string - var err error - - // If root and path are equal, then dir must be empty and the glob must - // be ".". - if filepath.Clean(root) == filepath.Clean(path) { - glob = "." - } else { - glob, err = filepath.Rel(root, path) - if err != nil { - return nil, err - } - } - - globStats, err := copier.Stat(root, "", copier.StatOptions{}, []string{glob}) - if err != nil { - return nil, err - } - - if len(globStats) != 1 { - return nil, fmt.Errorf("internal error: secureStat: expected 1 item but got %d", len(globStats)) - } - if len(globStats) != 1 { - return nil, fmt.Errorf("internal error: secureStat: expected 1 result but got %d", len(globStats[0].Results)) - } - - // NOTE: the key in the map differ from `glob` when hitting symlink. - // Hence, we just take the first (and only) key/value pair. - for _, stat := range globStats[0].Results { - var statErr error - if stat.Error != "" { - statErr = errors.New(stat.Error) - } - // If necessary evaluate the symlink - if stat.IsSymlink { - target, err := copier.Eval(root, path, copier.EvalOptions{}) - if err != nil { - return nil, fmt.Errorf("evaluating symlink in container: %w", err) - } - // Need to make sure the symlink is relative to the root! - target = strings.TrimPrefix(target, root) - target = filepath.Join("/", target) - stat.ImmediateTarget = target - } - return stat, statErr - } - - // Nothing found! - return nil, copy.ErrENOENT + // If the container is NOT running, we need to resolve the path + // on the host. + return c.statOnHost(mountPoint, containerPath) } diff --git a/libpod/container_stat_unsupported.go b/libpod/container_stat_unsupported.go index 2f1acd44d..e88b88bb1 100644 --- a/libpod/container_stat_unsupported.go +++ b/libpod/container_stat_unsupported.go @@ -1,5 +1,5 @@ -//go:build !linux -// +build !linux +//go:build !linux && !freebsd +// +build !linux,!freebsd package libpod diff --git a/libpod/events/logfile.go b/libpod/events/logfile.go index d749a0d4d..bb0f461e3 100644 --- a/libpod/events/logfile.go +++ b/libpod/events/logfile.go @@ -9,7 +9,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "os" "path" "path/filepath" @@ -204,11 +203,11 @@ func truncate(filePath string) error { size := origFinfo.Size() threshold := size / 2 - tmp, err := ioutil.TempFile(path.Dir(filePath), "") + tmp, err := os.CreateTemp(path.Dir(filePath), "") if err != nil { // Retry in /tmp in case creating a tmp file in the same // directory has failed. - tmp, err = ioutil.TempFile("", "") + tmp, err = os.CreateTemp("", "") if err != nil { return err } diff --git a/libpod/events/logfile_test.go b/libpod/events/logfile_test.go index 302533c12..50141168e 100644 --- a/libpod/events/logfile_test.go +++ b/libpod/events/logfile_test.go @@ -1,7 +1,6 @@ package events import ( - "io/ioutil" "os" "testing" @@ -29,7 +28,7 @@ func TestRotateLog(t *testing.T) { } for _, test := range tests { - tmp, err := ioutil.TempFile("", "log-rotation-") + tmp, err := os.CreateTemp("", "log-rotation-") require.NoError(t, err) defer os.Remove(tmp.Name()) defer tmp.Close() @@ -84,7 +83,7 @@ func TestTruncationOutput(t *testing.T) { 10 ` // Create dummy file - tmp, err := ioutil.TempFile("", "log-rotation") + tmp, err := os.CreateTemp("", "log-rotation") require.NoError(t, err) defer os.Remove(tmp.Name()) defer tmp.Close() @@ -94,11 +93,11 @@ func TestTruncationOutput(t *testing.T) { require.NoError(t, err) // Truncate the file - beforeTruncation, err := ioutil.ReadFile(tmp.Name()) + beforeTruncation, err := os.ReadFile(tmp.Name()) require.NoError(t, err) err = truncate(tmp.Name()) require.NoError(t, err) - afterTruncation, err := ioutil.ReadFile(tmp.Name()) + afterTruncation, err := os.ReadFile(tmp.Name()) require.NoError(t, err) // Test if rotation was successful @@ -116,9 +115,9 @@ func TestRenameLog(t *testing.T) { 5 ` // Create two dummy files - source, err := ioutil.TempFile("", "removing") + source, err := os.CreateTemp("", "removing") require.NoError(t, err) - target, err := ioutil.TempFile("", "renaming") + target, err := os.CreateTemp("", "renaming") require.NoError(t, err) // Write to source dummy file @@ -126,11 +125,11 @@ func TestRenameLog(t *testing.T) { require.NoError(t, err) // Rename the files - beforeRename, err := ioutil.ReadFile(source.Name()) + beforeRename, err := os.ReadFile(source.Name()) require.NoError(t, err) err = renameLog(source.Name(), target.Name()) require.NoError(t, err) - afterRename, err := ioutil.ReadFile(target.Name()) + afterRename, err := os.ReadFile(target.Name()) require.NoError(t, err) // Test if renaming was successful diff --git a/libpod/healthcheck.go b/libpod/healthcheck.go index e835af9f0..a589f2787 100644 --- a/libpod/healthcheck.go +++ b/libpod/healthcheck.go @@ -5,7 +5,6 @@ import ( "context" "errors" "fmt" - "io/ioutil" "os" "path/filepath" "strings" @@ -208,7 +207,7 @@ func (c *Container) updateHealthStatus(status string) error { if err != nil { return fmt.Errorf("unable to marshall healthchecks for writing status: %w", err) } - return ioutil.WriteFile(c.healthCheckLogPath(), newResults, 0700) + return os.WriteFile(c.healthCheckLogPath(), newResults, 0700) } // UpdateHealthCheckLog parses the health check results and writes the log @@ -242,7 +241,7 @@ func (c *Container) updateHealthCheckLog(hcl define.HealthCheckLog, inStartPerio if err != nil { return fmt.Errorf("unable to marshall healthchecks for writing: %w", err) } - return ioutil.WriteFile(c.healthCheckLogPath(), newResults, 0700) + return os.WriteFile(c.healthCheckLogPath(), newResults, 0700) } // HealthCheckLogPath returns the path for where the health check log is @@ -259,7 +258,7 @@ func (c *Container) getHealthCheckLog() (define.HealthCheckResults, error) { if _, err := os.Stat(c.healthCheckLogPath()); os.IsNotExist(err) { return healthCheck, nil } - b, err := ioutil.ReadFile(c.healthCheckLogPath()) + b, err := os.ReadFile(c.healthCheckLogPath()) if err != nil { return healthCheck, fmt.Errorf("failed to read health check log file: %w", err) } diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go index e27ec8e9d..6ea56ade5 100644 --- a/libpod/networking_linux.go +++ b/libpod/networking_linux.go @@ -8,7 +8,6 @@ import ( "crypto/sha256" "errors" "fmt" - "io/ioutil" "net" "os" "os/exec" @@ -303,7 +302,7 @@ func (r *RootlessNetNS) Cleanup(runtime *Runtime) error { if err != nil { logrus.Error(err) } - b, err := ioutil.ReadFile(r.getPath(rootlessNetNsSilrp4netnsPidFile)) + b, err := os.ReadFile(r.getPath(rootlessNetNsSilrp4netnsPidFile)) if err == nil { var i int i, err = strconv.Atoi(string(b)) @@ -445,7 +444,7 @@ func (r *Runtime) GetRootlessNetNs(new bool) (*RootlessNetNS, error) { // create pid file for the slirp4netns process // this is need to kill the process in the cleanup pid := strconv.Itoa(cmd.Process.Pid) - err = ioutil.WriteFile(filepath.Join(rootlessNetNsDir, rootlessNetNsSilrp4netnsPidFile), []byte(pid), 0700) + err = os.WriteFile(filepath.Join(rootlessNetNsDir, rootlessNetNsSilrp4netnsPidFile), []byte(pid), 0700) if err != nil { return nil, fmt.Errorf("unable to write rootless-netns slirp4netns pid file: %w", err) } diff --git a/libpod/networking_machine.go b/libpod/networking_machine.go index 7b8eb94df..dce335c0a 100644 --- a/libpod/networking_machine.go +++ b/libpod/networking_machine.go @@ -6,7 +6,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "net" "net/http" "strconv" @@ -109,7 +108,7 @@ func makeMachineRequest(ctx context.Context, client *http.Client, url string, bu } func annotateGvproxyResponseError(r io.Reader) error { - b, err := ioutil.ReadAll(r) + b, err := io.ReadAll(r) if err == nil && len(b) > 0 { return fmt.Errorf("something went wrong with the request: %q", string(b)) } diff --git a/libpod/networking_slirp4netns.go b/libpod/networking_slirp4netns.go index d4ec9082b..4026b6b48 100644 --- a/libpod/networking_slirp4netns.go +++ b/libpod/networking_slirp4netns.go @@ -8,7 +8,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "net" "os" "os/exec" @@ -324,7 +323,7 @@ func (r *Runtime) setupSlirp4netns(ctr *Container, netns ns.NetNS) error { // correct value assigned so DAD is disabled for it // Also make sure to change this value back to the original after slirp4netns // is ready in case users rely on this sysctl. - orgValue, err := ioutil.ReadFile(ipv6ConfDefaultAcceptDadSysctl) + orgValue, err := os.ReadFile(ipv6ConfDefaultAcceptDadSysctl) if err != nil { netnsReadyWg.Done() // on ipv6 disabled systems the sysctl does not exists @@ -334,7 +333,7 @@ func (r *Runtime) setupSlirp4netns(ctr *Container, netns ns.NetNS) error { } return err } - err = ioutil.WriteFile(ipv6ConfDefaultAcceptDadSysctl, []byte("0"), 0644) + err = os.WriteFile(ipv6ConfDefaultAcceptDadSysctl, []byte("0"), 0644) netnsReadyWg.Done() if err != nil { return err @@ -342,7 +341,7 @@ func (r *Runtime) setupSlirp4netns(ctr *Container, netns ns.NetNS) error { // wait until slirp4nets is ready before resetting this value slirpReadyWg.Wait() - return ioutil.WriteFile(ipv6ConfDefaultAcceptDadSysctl, orgValue, 0644) + return os.WriteFile(ipv6ConfDefaultAcceptDadSysctl, orgValue, 0644) }) if err != nil { logrus.Warnf("failed to set net.ipv6.conf.default.accept_dad sysctl: %v", err) @@ -486,7 +485,7 @@ func waitForSync(syncR *os.File, cmd *exec.Cmd, logFile io.ReadSeeker, timeout t if _, err := logFile.Seek(0, 0); err != nil { logrus.Errorf("Could not seek log file: %q", err) } - logContent, err := ioutil.ReadAll(logFile) + logContent, err := io.ReadAll(logFile) if err != nil { return fmt.Errorf("%s failed: %w", prog, err) } @@ -730,7 +729,7 @@ func (c *Container) reloadRootlessRLKPortMapping() error { if err != nil { return fmt.Errorf("port reloading failed: %w", err) } - b, err := ioutil.ReadAll(conn) + b, err := io.ReadAll(conn) if err != nil { return fmt.Errorf("port reloading failed: %w", err) } diff --git a/libpod/oci_conmon_common.go b/libpod/oci_conmon_common.go index 53dddd064..cbdbad02d 100644 --- a/libpod/oci_conmon_common.go +++ b/libpod/oci_conmon_common.go @@ -10,7 +10,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "net" "net/http" "os" @@ -232,7 +231,7 @@ func (r *ConmonOCIRuntime) UpdateContainerStatus(ctr *Container) error { } if err := cmd.Start(); err != nil { - out, err2 := ioutil.ReadAll(errPipe) + out, err2 := io.ReadAll(errPipe) if err2 != nil { return fmt.Errorf("getting container %s state: %w", ctr.ID(), err) } @@ -254,7 +253,7 @@ func (r *ConmonOCIRuntime) UpdateContainerStatus(ctr *Container) error { if err := errPipe.Close(); err != nil { return err } - out, err := ioutil.ReadAll(outPipe) + out, err := io.ReadAll(outPipe) if err != nil { return fmt.Errorf("reading stdout: %s: %w", ctr.ID(), err) } @@ -335,7 +334,7 @@ func generateResourceFile(res *spec.LinuxResources) (string, []string, error) { return "", flags, nil } - f, err := ioutil.TempFile("", "podman") + f, err := os.CreateTemp("", "podman") if err != nil { return "", nil, err } @@ -1398,7 +1397,7 @@ func newPipe() (*os.File, *os.File, error) { func readConmonPidFile(pidFile string) (int, error) { // Let's try reading the Conmon pid at the same time. if pidFile != "" { - contents, err := ioutil.ReadFile(pidFile) + contents, err := os.ReadFile(pidFile) if err != nil { return -1, err } @@ -1447,7 +1446,7 @@ func readConmonPipeData(runtimeName string, pipe *os.File, ociLog string) (int, case ss := <-ch: if ss.err != nil { if ociLog != "" { - ociLogData, err := ioutil.ReadFile(ociLog) + ociLogData, err := os.ReadFile(ociLog) if err == nil { var ociErr ociError if err := json.Unmarshal(ociLogData, &ociErr); err == nil { @@ -1460,7 +1459,7 @@ func readConmonPipeData(runtimeName string, pipe *os.File, ociLog string) (int, logrus.Debugf("Received: %d", ss.si.Data) if ss.si.Data < 0 { if ociLog != "" { - ociLogData, err := ioutil.ReadFile(ociLog) + ociLogData, err := os.ReadFile(ociLog) if err == nil { var ociErr ociError if err := json.Unmarshal(ociLogData, &ociErr); err == nil { diff --git a/libpod/oci_conmon_exec_common.go b/libpod/oci_conmon_exec_common.go index e5080942b..24113bd8d 100644 --- a/libpod/oci_conmon_exec_common.go +++ b/libpod/oci_conmon_exec_common.go @@ -3,7 +3,6 @@ package libpod import ( "errors" "fmt" - "io/ioutil" "net/http" "os" "os/exec" @@ -665,7 +664,7 @@ func attachExecHTTP(c *Container, sessionID string, r *http.Request, w http.Resp // prepareProcessExec returns the path of the process.json used in runc exec -p // caller is responsible to close the returned *os.File if needed. func (c *Container) prepareProcessExec(options *ExecOptions, env []string, sessionID string) (*os.File, error) { - f, err := ioutil.TempFile(c.execBundlePath(sessionID), "exec-process-") + f, err := os.CreateTemp(c.execBundlePath(sessionID), "exec-process-") if err != nil { return nil, err } @@ -764,7 +763,7 @@ func (c *Container) prepareProcessExec(options *ExecOptions, env []string, sessi return nil, err } - if err := ioutil.WriteFile(f.Name(), processJSON, 0644); err != nil { + if err := os.WriteFile(f.Name(), processJSON, 0644); err != nil { return nil, err } return f, nil diff --git a/libpod/plugin/volume_api.go b/libpod/plugin/volume_api.go index 522895798..c595937ae 100644 --- a/libpod/plugin/volume_api.go +++ b/libpod/plugin/volume_api.go @@ -5,7 +5,7 @@ import ( "context" "errors" "fmt" - "io/ioutil" + "io" "net" "net/http" "os" @@ -95,7 +95,7 @@ func validatePlugin(newPlugin *VolumePlugin) error { } // Read and decode the body so we can tell if this is a volume plugin. - respBytes, err := ioutil.ReadAll(resp.Body) + respBytes, err := io.ReadAll(resp.Body) if err != nil { return fmt.Errorf("reading activation response body from plugin %s: %w", newPlugin.Name, err) } @@ -252,7 +252,7 @@ func (p *VolumePlugin) handleErrorResponse(resp *http.Response, endpoint, volNam // Let's interpret anything other than 200 as an error. // If there isn't an error, don't even bother decoding the response. if resp.StatusCode != 200 { - errResp, err := ioutil.ReadAll(resp.Body) + errResp, err := io.ReadAll(resp.Body) if err != nil { return fmt.Errorf("reading response body from volume plugin %s: %w", p.Name, err) } @@ -307,7 +307,7 @@ func (p *VolumePlugin) ListVolumes() ([]*volume.Volume, error) { return nil, err } - volumeRespBytes, err := ioutil.ReadAll(resp.Body) + volumeRespBytes, err := io.ReadAll(resp.Body) if err != nil { return nil, fmt.Errorf("reading response body from volume plugin %s: %w", p.Name, err) } @@ -342,7 +342,7 @@ func (p *VolumePlugin) GetVolume(req *volume.GetRequest) (*volume.Volume, error) return nil, err } - getRespBytes, err := ioutil.ReadAll(resp.Body) + getRespBytes, err := io.ReadAll(resp.Body) if err != nil { return nil, fmt.Errorf("reading response body from volume plugin %s: %w", p.Name, err) } @@ -398,7 +398,7 @@ func (p *VolumePlugin) GetVolumePath(req *volume.PathRequest) (string, error) { return "", err } - pathRespBytes, err := ioutil.ReadAll(resp.Body) + pathRespBytes, err := io.ReadAll(resp.Body) if err != nil { return "", fmt.Errorf("reading response body from volume plugin %s: %w", p.Name, err) } @@ -435,7 +435,7 @@ func (p *VolumePlugin) MountVolume(req *volume.MountRequest) (string, error) { return "", err } - mountRespBytes, err := ioutil.ReadAll(resp.Body) + mountRespBytes, err := io.ReadAll(resp.Body) if err != nil { return "", fmt.Errorf("reading response body from volume plugin %s: %w", p.Name, err) } diff --git a/libpod/runtime_img.go b/libpod/runtime_img.go index dacbd752f..87b77c3eb 100644 --- a/libpod/runtime_img.go +++ b/libpod/runtime_img.go @@ -5,7 +5,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "os" buildahDefine "github.com/containers/buildah/define" @@ -105,7 +104,7 @@ func (r *Runtime) Build(ctx context.Context, options buildahDefine.BuildOptions, // DownloadFromFile reads all of the content from the reader and temporarily // saves in it $TMPDIR/importxyz, which is deleted after the image is imported func DownloadFromFile(reader *os.File) (string, error) { - outFile, err := ioutil.TempFile(util.Tmpdir(), "import") + outFile, err := os.CreateTemp(util.Tmpdir(), "import") if err != nil { return "", fmt.Errorf("creating file: %w", err) } diff --git a/libpod/runtime_migrate.go b/libpod/runtime_migrate.go index 36901d4d0..df1a1f1cb 100644 --- a/libpod/runtime_migrate.go +++ b/libpod/runtime_migrate.go @@ -5,7 +5,6 @@ package libpod import ( "fmt" - "io/ioutil" "os" "path/filepath" "strconv" @@ -23,7 +22,7 @@ func (r *Runtime) stopPauseProcess() error { if err != nil { return fmt.Errorf("could not get pause process pid file path: %w", err) } - data, err := ioutil.ReadFile(pausePidPath) + data, err := os.ReadFile(pausePidPath) if err != nil { if os.IsNotExist(err) { return nil diff --git a/libpod/state_test.go b/libpod/state_test.go index 3c1fe8f63..7664f7c00 100644 --- a/libpod/state_test.go +++ b/libpod/state_test.go @@ -1,7 +1,6 @@ package libpod import ( - "io/ioutil" "os" "path/filepath" "strings" @@ -35,7 +34,7 @@ var ( // Get an empty BoltDB state for use in tests func getEmptyBoltState() (_ State, _ string, _ lock.Manager, retErr error) { - tmpDir, err := ioutil.TempDir("", tmpDirPrefix) + tmpDir, err := os.MkdirTemp("", tmpDirPrefix) if err != nil { return nil, "", nil, err } |