summaryrefslogtreecommitdiff
path: root/libpod
diff options
context:
space:
mode:
Diffstat (limited to 'libpod')
-rw-r--r--libpod/container_internal_linux.go63
-rw-r--r--libpod/container_path_resolution.go47
2 files changed, 92 insertions, 18 deletions
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index b41a3fa38..6c9489a08 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -174,25 +174,60 @@ func (c *Container) prepare() error {
return err
}
- // Ensure container entrypoint is created (if required)
- if c.config.CreateWorkingDir {
- workdir, err := securejoin.SecureJoin(c.state.Mountpoint, c.WorkingDir())
- if err != nil {
- return errors.Wrapf(err, "error creating path to container %s working dir", c.ID())
- }
- rootUID := c.RootUID()
- rootGID := c.RootGID()
+ // Make sure the workdir exists
+ if err := c.resolveWorkDir(); err != nil {
+ return err
+ }
- if err := os.MkdirAll(workdir, 0755); err != nil {
- if os.IsExist(err) {
- return nil
+ return nil
+}
+
+// resolveWorkDir resolves the container's workdir and, depending on the
+// configuration, will create it, or error out if it does not exist.
+// Note that the container must be mounted before.
+func (c *Container) resolveWorkDir() error {
+ workdir := c.WorkingDir()
+
+ // If the specified workdir is a subdir of a volume or mount,
+ // we don't need to do anything. The runtime is taking care of
+ // that.
+ if isPathOnVolume(c, workdir) || isPathOnBindMount(c, workdir) {
+ logrus.Debugf("Workdir %q resolved to a volume or mount", workdir)
+ return nil
+ }
+
+ _, resolvedWorkdir, err := c.resolvePath(c.state.Mountpoint, workdir)
+ if err != nil {
+ return err
+ }
+ logrus.Debugf("Workdir %q resolved to host path %q", workdir, resolvedWorkdir)
+
+ // No need to create it (e.g., `--workdir=/foo`), so let's make sure
+ // the path exists on the container.
+ if !c.config.CreateWorkingDir {
+ if _, err := os.Stat(resolvedWorkdir); err != nil {
+ if os.IsNotExist(err) {
+ return errors.Errorf("workdir %q does not exist on container %s", workdir, c.ID())
}
- return errors.Wrapf(err, "error creating container %s working dir", c.ID())
+ // This might be a serious error (e.g., permission), so
+ // we need to return the full error.
+ return errors.Wrapf(err, "error detecting workdir %q on container %s", workdir, c.ID())
}
+ }
+
+ // Ensure container entrypoint is created (if required).
+ rootUID := c.RootUID()
+ rootGID := c.RootGID()
- if err := os.Chown(workdir, rootUID, rootGID); err != nil {
- return errors.Wrapf(err, "error chowning container %s working directory to container root", c.ID())
+ if err := os.MkdirAll(resolvedWorkdir, 0755); err != nil {
+ if os.IsExist(err) {
+ return nil
}
+ return errors.Wrapf(err, "error creating container %s workdir", c.ID())
+ }
+
+ if err := os.Chown(resolvedWorkdir, rootUID, rootGID); err != nil {
+ return errors.Wrapf(err, "error chowning container %s workdir to container root", c.ID())
}
return nil
diff --git a/libpod/container_path_resolution.go b/libpod/container_path_resolution.go
index 68f174278..805b3b947 100644
--- a/libpod/container_path_resolution.go
+++ b/libpod/container_path_resolution.go
@@ -13,6 +13,11 @@ import (
// resolveContainerPaths resolves the container's mount point and the container
// path as specified by the user. Both may resolve to paths outside of the
// container's mount point when the container path hits a volume or bind mount.
+//
+// It returns a bool, indicating whether containerPath resolves outside of
+// mountPoint (e.g., via a mount or volume), the resolved root (e.g., container
+// mount, bind mount or volume) and the resolved path on the root (absolute to
+// the host).
func (container *Container) resolvePath(mountPoint string, containerPath string) (string, string, error) {
// Let's first make sure we have a path relative to the mount point.
pathRelativeToContainerMountPoint := containerPath
@@ -97,8 +102,8 @@ func (container *Container) resolvePath(mountPoint string, containerPath string)
return mountPoint, resolvedPathOnTheContainerMountPoint, nil
}
-// findVolume checks if the specified container path matches a volume inside
-// the container. It returns a matching volume or nil.
+// findVolume checks if the specified containerPath matches the destination
+// path of a Volume. Returns a matching Volume or nil.
func findVolume(c *Container, containerPath string) (*Volume, error) {
runtime := c.Runtime()
cleanedContainerPath := filepath.Clean(containerPath)
@@ -110,8 +115,25 @@ func findVolume(c *Container, containerPath string) (*Volume, error) {
return nil, nil
}
-// findBindMount checks if the specified container path matches a bind mount
-// inside the container. It returns a matching mount or nil.
+// isPathOnVolume returns true if the specified containerPath is a subdir of any
+// Volume's destination.
+func isPathOnVolume(c *Container, containerPath string) bool {
+ cleanedContainerPath := filepath.Clean(containerPath)
+ for _, vol := range c.Config().NamedVolumes {
+ if cleanedContainerPath == filepath.Clean(vol.Dest) {
+ return true
+ }
+ for dest := vol.Dest; dest != "/"; dest = filepath.Dir(dest) {
+ if cleanedContainerPath == dest {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+// findBindMounts checks if the specified containerPath matches the destination
+// path of a Mount. Returns a matching Mount or nil.
func findBindMount(c *Container, containerPath string) *specs.Mount {
cleanedPath := filepath.Clean(containerPath)
for _, m := range c.Config().Spec.Mounts {
@@ -125,3 +147,20 @@ func findBindMount(c *Container, containerPath string) *specs.Mount {
}
return nil
}
+
+/// isPathOnBindMount returns true if the specified containerPath is a subdir of any
+// Mount's destination.
+func isPathOnBindMount(c *Container, containerPath string) bool {
+ cleanedContainerPath := filepath.Clean(containerPath)
+ for _, m := range c.Config().Spec.Mounts {
+ if cleanedContainerPath == filepath.Clean(m.Destination) {
+ return true
+ }
+ for dest := m.Destination; dest != "/"; dest = filepath.Dir(dest) {
+ if cleanedContainerPath == dest {
+ return true
+ }
+ }
+ }
+ return false
+}