mirror of
https://github.com/opencontainers/runc.git
synced 2025-10-03 06:42:22 +08:00
libcontainer/cgroups/fscommon: introduce OpenFile
Move the functionality of opening a cgroup file into a separate function, OpenFile, which, similar to ReadFile and WriteFile, use separate dir and file arguments. Change ReadFile and WriteFile to rely on OpenFile, and use lower-level read and write instead of ones from ioutil. It changes the semantics of WriteFile a bit -- it no longer uses O_CREAT flag. This is good for real cgroup as there is no need to try creating the files in there, but can potentially break WriteFile users -- previously, EPERM error was returned for non-existing files, and now it's ENOENT. This also breaks the fs/fs2 unit tests since they write to pseudo-cgroup files inside a test directory (not to a real cgroup fs), and now fscommon.WriteFile do not create or truncate files, so we have to add a variable that is set by the unit tests. Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
This commit is contained in:
@@ -17,6 +17,10 @@ import (
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
)
|
||||
|
||||
func init() {
|
||||
fscommon.TestMode = true
|
||||
}
|
||||
|
||||
type cgroupTestUtil struct {
|
||||
// cgroup data to use in tests.
|
||||
CgroupData *cgroupData
|
||||
|
@@ -3,10 +3,9 @@
|
||||
package fscommon
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"bytes"
|
||||
"os"
|
||||
|
||||
securejoin "github.com/cyphar/filepath-securejoin"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/sys/unix"
|
||||
@@ -15,14 +14,12 @@ import (
|
||||
// WriteFile writes data to a cgroup file in dir.
|
||||
// It is supposed to be used for cgroup files only.
|
||||
func WriteFile(dir, file, data string) error {
|
||||
if dir == "" {
|
||||
return errors.Errorf("no directory specified for %s", file)
|
||||
}
|
||||
path, err := securejoin.SecureJoin(dir, file)
|
||||
fd, err := OpenFile(dir, file, unix.O_WRONLY)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := retryingWriteFile(path, []byte(data), 0700); err != nil {
|
||||
defer fd.Close()
|
||||
if err := retryingWriteFile(fd, data); err != nil {
|
||||
return errors.Wrapf(err, "failed to write %q", data)
|
||||
}
|
||||
return nil
|
||||
@@ -31,22 +28,21 @@ func WriteFile(dir, file, data string) error {
|
||||
// ReadFile reads data from a cgroup file in dir.
|
||||
// It is supposed to be used for cgroup files only.
|
||||
func ReadFile(dir, file string) (string, error) {
|
||||
if dir == "" {
|
||||
return "", errors.Errorf("no directory specified for %s", file)
|
||||
}
|
||||
path, err := securejoin.SecureJoin(dir, file)
|
||||
fd, err := OpenFile(dir, file, unix.O_RDONLY)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
data, err := ioutil.ReadFile(path)
|
||||
return string(data), err
|
||||
var buf bytes.Buffer
|
||||
|
||||
_, err = buf.ReadFrom(fd)
|
||||
return buf.String(), err
|
||||
}
|
||||
|
||||
func retryingWriteFile(filename string, data []byte, perm os.FileMode) error {
|
||||
func retryingWriteFile(fd *os.File, data string) error {
|
||||
for {
|
||||
err := ioutil.WriteFile(filename, data, perm)
|
||||
_, err := fd.Write([]byte(data))
|
||||
if errors.Is(err, unix.EINTR) {
|
||||
logrus.Infof("interrupted while writing %s to %s", string(data), filename)
|
||||
logrus.Infof("interrupted while writing %s to %s", data, fd.Name())
|
||||
continue
|
||||
}
|
||||
return err
|
||||
|
33
libcontainer/cgroups/fscommon/open.go
Normal file
33
libcontainer/cgroups/fscommon/open.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package fscommon
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
securejoin "github.com/cyphar/filepath-securejoin"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
// Set to true by fs unit tests
|
||||
TestMode bool
|
||||
)
|
||||
|
||||
// OpenFile opens a cgroup file in a given dir with given flags.
|
||||
// It is supposed to be used for cgroup files only.
|
||||
func OpenFile(dir, file string, flags int) (*os.File, error) {
|
||||
if dir == "" {
|
||||
return nil, errors.Errorf("no directory specified for %s", file)
|
||||
}
|
||||
mode := os.FileMode(0)
|
||||
if TestMode && flags&os.O_WRONLY != 0 {
|
||||
// "emulate" cgroup fs for unit tests
|
||||
flags |= os.O_TRUNC | os.O_CREATE
|
||||
mode = 0o600
|
||||
}
|
||||
path, err := securejoin.SecureJoin(dir, file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return os.OpenFile(path, flags, mode)
|
||||
}
|
Reference in New Issue
Block a user