mirror of
https://github.com/opencontainers/runc.git
synced 2025-10-05 15:37:02 +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"
|
"github.com/opencontainers/runc/libcontainer/configs"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
fscommon.TestMode = true
|
||||||
|
}
|
||||||
|
|
||||||
type cgroupTestUtil struct {
|
type cgroupTestUtil struct {
|
||||||
// cgroup data to use in tests.
|
// cgroup data to use in tests.
|
||||||
CgroupData *cgroupData
|
CgroupData *cgroupData
|
||||||
|
@@ -3,10 +3,9 @@
|
|||||||
package fscommon
|
package fscommon
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"bytes"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
securejoin "github.com/cyphar/filepath-securejoin"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
@@ -15,14 +14,12 @@ import (
|
|||||||
// WriteFile writes data to a cgroup file in dir.
|
// WriteFile writes data to a cgroup file in dir.
|
||||||
// It is supposed to be used for cgroup files only.
|
// It is supposed to be used for cgroup files only.
|
||||||
func WriteFile(dir, file, data string) error {
|
func WriteFile(dir, file, data string) error {
|
||||||
if dir == "" {
|
fd, err := OpenFile(dir, file, unix.O_WRONLY)
|
||||||
return errors.Errorf("no directory specified for %s", file)
|
|
||||||
}
|
|
||||||
path, err := securejoin.SecureJoin(dir, file)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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 errors.Wrapf(err, "failed to write %q", data)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -31,22 +28,21 @@ func WriteFile(dir, file, data string) error {
|
|||||||
// ReadFile reads data from a cgroup file in dir.
|
// ReadFile reads data from a cgroup file in dir.
|
||||||
// It is supposed to be used for cgroup files only.
|
// It is supposed to be used for cgroup files only.
|
||||||
func ReadFile(dir, file string) (string, error) {
|
func ReadFile(dir, file string) (string, error) {
|
||||||
if dir == "" {
|
fd, err := OpenFile(dir, file, unix.O_RDONLY)
|
||||||
return "", errors.Errorf("no directory specified for %s", file)
|
|
||||||
}
|
|
||||||
path, err := securejoin.SecureJoin(dir, file)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
data, err := ioutil.ReadFile(path)
|
var buf bytes.Buffer
|
||||||
return string(data), err
|
|
||||||
|
_, 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 {
|
for {
|
||||||
err := ioutil.WriteFile(filename, data, perm)
|
_, err := fd.Write([]byte(data))
|
||||||
if errors.Is(err, unix.EINTR) {
|
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
|
continue
|
||||||
}
|
}
|
||||||
return err
|
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