github.com/containers/podman/v2@v2.2.2-0.20210501105131-c1e07d070c4c/libpod/util_linux.go (about)

     1  // +build linux
     2  
     3  package libpod
     4  
     5  import (
     6  	"fmt"
     7  	"strings"
     8  	"syscall"
     9  
    10  	"github.com/containers/podman/v2/libpod/define"
    11  	"github.com/containers/podman/v2/pkg/cgroups"
    12  	"github.com/containers/podman/v2/pkg/rootless"
    13  	"github.com/opencontainers/selinux/go-selinux/label"
    14  	"github.com/pkg/errors"
    15  	"github.com/sirupsen/logrus"
    16  	"golang.org/x/sys/unix"
    17  )
    18  
    19  // systemdSliceFromPath makes a new systemd slice under the given parent with
    20  // the given name.
    21  // The parent must be a slice. The name must NOT include ".slice"
    22  func systemdSliceFromPath(parent, name string) (string, error) {
    23  	cgroupPath, err := assembleSystemdCgroupName(parent, name)
    24  	if err != nil {
    25  		return "", err
    26  	}
    27  
    28  	logrus.Debugf("Created cgroup path %s for parent %s and name %s", cgroupPath, parent, name)
    29  
    30  	if err := makeSystemdCgroup(cgroupPath); err != nil {
    31  		return "", errors.Wrapf(err, "error creating cgroup %s", cgroupPath)
    32  	}
    33  
    34  	logrus.Debugf("Created cgroup %s", cgroupPath)
    35  
    36  	return cgroupPath, nil
    37  }
    38  
    39  func getDefaultSystemdCgroup() string {
    40  	if rootless.IsRootless() {
    41  		return SystemdDefaultRootlessCgroupParent
    42  	}
    43  	return SystemdDefaultCgroupParent
    44  }
    45  
    46  // makeSystemdCgroup creates a systemd CGroup at the given location.
    47  func makeSystemdCgroup(path string) error {
    48  	controller, err := cgroups.NewSystemd(getDefaultSystemdCgroup())
    49  	if err != nil {
    50  		return err
    51  	}
    52  
    53  	if rootless.IsRootless() {
    54  		return controller.CreateSystemdUserUnit(path, rootless.GetRootlessUID())
    55  	}
    56  	return controller.CreateSystemdUnit(path)
    57  }
    58  
    59  // deleteSystemdCgroup deletes the systemd cgroup at the given location
    60  func deleteSystemdCgroup(path string) error {
    61  	controller, err := cgroups.NewSystemd(getDefaultSystemdCgroup())
    62  	if err != nil {
    63  		return err
    64  	}
    65  	if rootless.IsRootless() {
    66  		conn, err := cgroups.GetUserConnection(rootless.GetRootlessUID())
    67  		if err != nil {
    68  			return err
    69  		}
    70  		defer conn.Close()
    71  		return controller.DeleteByPathConn(path, conn)
    72  	}
    73  
    74  	return controller.DeleteByPath(path)
    75  }
    76  
    77  // assembleSystemdCgroupName creates a systemd cgroup path given a base and
    78  // a new component to add.
    79  // The base MUST be systemd slice (end in .slice)
    80  func assembleSystemdCgroupName(baseSlice, newSlice string) (string, error) {
    81  	const sliceSuffix = ".slice"
    82  
    83  	if !strings.HasSuffix(baseSlice, sliceSuffix) {
    84  		return "", errors.Wrapf(define.ErrInvalidArg, "cannot assemble cgroup path with base %q - must end in .slice", baseSlice)
    85  	}
    86  
    87  	noSlice := strings.TrimSuffix(baseSlice, sliceSuffix)
    88  	final := fmt.Sprintf("%s/%s-%s%s", baseSlice, noSlice, newSlice, sliceSuffix)
    89  
    90  	return final, nil
    91  }
    92  
    93  var lvpRelabel = label.Relabel
    94  var lvpInitLabels = label.InitLabels
    95  var lvpReleaseLabel = label.ReleaseLabel
    96  
    97  // LabelVolumePath takes a mount path for a volume and gives it an
    98  // selinux label of either shared or not
    99  func LabelVolumePath(path string) error {
   100  	_, mountLabel, err := lvpInitLabels([]string{})
   101  	if err != nil {
   102  		return errors.Wrapf(err, "error getting default mountlabels")
   103  	}
   104  	if err := lvpReleaseLabel(mountLabel); err != nil {
   105  		return errors.Wrapf(err, "error releasing label %q", mountLabel)
   106  	}
   107  
   108  	if err := lvpRelabel(path, mountLabel, true); err != nil {
   109  		if err == syscall.ENOTSUP {
   110  			logrus.Debugf("Labeling not supported on %q", path)
   111  		} else {
   112  			return errors.Wrapf(err, "error setting selinux label for %s to %q as shared", path, mountLabel)
   113  		}
   114  	}
   115  	return nil
   116  }
   117  
   118  // Unmount umounts a target directory
   119  func Unmount(mount string) {
   120  	if err := unix.Unmount(mount, unix.MNT_DETACH); err != nil {
   121  		if err != syscall.EINVAL {
   122  			logrus.Warnf("failed to unmount %s : %v", mount, err)
   123  		} else {
   124  			logrus.Debugf("failed to unmount %s : %v", mount, err)
   125  		}
   126  	}
   127  }