k3s/vendor/github.com/rootless-containers/rootlesskit/pkg/copyup/tmpfssymlink/tmpfssymlink.go

83 lines
2.4 KiB
Go

package tmpfssymlink
import (
"io/ioutil"
"os"
"path/filepath"
"golang.org/x/sys/unix"
"github.com/pkg/errors"
"github.com/rootless-containers/rootlesskit/pkg/copyup"
)
func NewChildDriver() copyup.ChildDriver {
return &childDriver{}
}
type childDriver struct {
}
func (d *childDriver) CopyUp(dirs []string) ([]string, error) {
// we create bind0 outside of StateDir so as to allow
// copying up /run with stateDir=/run/user/1001/rootlesskit/default.
bind0, err := ioutil.TempDir("/tmp", "rootlesskit-b")
if err != nil {
return nil, errors.Wrap(err, "creating bind0 directory under /tmp")
}
defer os.RemoveAll(bind0)
var copied []string
for _, d := range dirs {
d := filepath.Clean(d)
if d == "/tmp" {
// TODO: we can support copy-up /tmp by changing bind0TempDir
return copied, errors.New("/tmp cannot be copied up")
}
if err := unix.Mount(d, bind0, "", uintptr(unix.MS_BIND|unix.MS_REC), ""); err != nil {
return copied, errors.Wrapf(err, "failed to create bind mount on %s", d)
}
if err := unix.Mount("none", d, "tmpfs", 0, ""); err != nil {
return copied, errors.Wrapf(err, "failed to mount tmpfs on %s", d)
}
bind1, err := ioutil.TempDir(d, ".ro")
if err != nil {
return copied, errors.Wrapf(err, "creating a directory under %s", d)
}
if err := unix.Mount(bind0, bind1, "", uintptr(unix.MS_MOVE), ""); err != nil {
return copied, errors.Wrapf(err, "failed to move mount point from %s to %s", bind0, bind1)
}
files, err := ioutil.ReadDir(bind1)
if err != nil {
return copied, errors.Wrapf(err, "reading dir %s", bind1)
}
for _, f := range files {
fFull := filepath.Join(bind1, f.Name())
var symlinkSrc string
if f.Mode()&os.ModeSymlink != 0 {
symlinkSrc, err = os.Readlink(fFull)
if err != nil {
return copied, errors.Wrapf(err, "reading dir %s", fFull)
}
} else {
symlinkSrc = filepath.Join(filepath.Base(bind1), f.Name())
}
symlinkDst := filepath.Join(d, f.Name())
// `mount` may create extra `/etc/mtab` after mounting empty tmpfs on /etc
// https://github.com/rootless-containers/rootlesskit/issues/45
if err = os.RemoveAll(symlinkDst); err != nil {
return copied, errors.Wrapf(err, "removing %s", symlinkDst)
}
if err := os.Symlink(symlinkSrc, symlinkDst); err != nil {
return copied, errors.Wrapf(err, "symlinking %s to %s", symlinkSrc, symlinkDst)
}
}
copied = append(copied, d)
}
return copied, nil
}