in integration/utils/exec.go [336:449]
func mountSetupFull(t *testing.T, stdout io.Writer, stderr io.Writer, user *UnixUser, rootSetup func(string) error, args ...string) *MountState {
t.Helper()
success := false
// Reset the test's umask to zero. This allows tests to not care about how the umask
// affects files, which can introduce subtle bugs in the tests themselves.
oldMask := unix.Umask(0)
defer func() {
if !success {
unix.Umask(oldMask)
}
}()
tempDir, err := ioutil.TempDir("", "test")
if err != nil {
t.Fatalf("Failed to create temporary directory: %v", err)
}
defer func() {
if !success {
os.RemoveAll(tempDir)
}
}()
root := filepath.Join(tempDir, "root")
mountPoint := filepath.Join(tempDir, "mnt")
MustMkdirAll(t, root, 0755)
MustMkdirAll(t, mountPoint, 0755)
if user != nil {
// Ensure all users can navigate through the temporary directory, which are often created with
// strict permissions.
if err := os.Chmod(tempDir, 0755); err != nil {
t.Fatalf("Failed to change permissions of %s", tempDir)
}
// The mount point must be owned by the user that will mount the FUSE file system.
if err := os.Chown(mountPoint, user.UID, user.GID); err != nil {
t.Fatalf("Failed to change ownership of %s", mountPoint)
}
}
realArgs := make([]string, 0, len(args)+1)
for _, arg := range args {
realArgs = append(realArgs, strings.Replace(arg, "%ROOT%", root, -1))
}
realArgs = append(realArgs, mountPoint)
if err := createDirsRequiredByMappings(root, realArgs...); err != nil {
t.Fatalf("Failed to create directories required by mappings: %v", err)
}
if rootSetup != nil {
if err := rootSetup(root); err != nil {
t.Fatalf("Failed to run custom rootSetup hook on %s: %v", root, err)
}
}
var storedStdout *bytes.Buffer
if stdout == os.Stdout {
storedStdout = new(bytes.Buffer)
stdout = storedStdout
}
var storedStderr *bytes.Buffer
if stderr == os.Stderr {
storedStderr = new(bytes.Buffer)
stderr = storedStderr
}
var cmd *exec.Cmd
var stdin io.WriteCloser
if !hasRootMapping(realArgs...) {
// Without a mapping at root, we can't wait for sandboxfs to come up using a cookie
// file. For now, we assume that only the reconfiguration tests do this as they get
// the same wait functionality by pushing an initial configuration request.
//
// TODO(jmmv): We shouldn't need to do this. Now that there is no more "static" and
// "dynamic" sandbox types, we could define initial root mappings in all cases and
// then let the reconfiguration take over. This is tricky because sandboxfs blocks
// when opening the input FIFO until there is a writer for it, which is not yet the
// case for our tests. And, with the work I'm planning to do on reconfigurations, I
// may drop the possibility of changing the root mapping.
cmd, stdin, err = startBackground("", stdout, stderr, user, realArgs...)
} else {
MustWriteFile(t, filepath.Join(root, ".cookie"), 0444, "")
cmd, stdin, err = startBackground(".cookie", stdout, stderr, user, realArgs...)
if err := os.Remove(filepath.Join(root, ".cookie")); err != nil {
t.Errorf("Failed to delete the startup cookie file: %v", err)
// Continue text execution. Failing hard here is a difficult condition to
// handle because sandboxfs is already running and we'd need to clean it up.
// It's easier to just let the test run, and it's actually beneficial to do
// so: many tests will work even if the removal failed, so the few tests
// that fail will hint at to what may be wrong.
}
if err != nil {
t.Fatalf("Failed to start sandboxfs: %v", err)
}
}
// All operations that can fail are now done. Setting success=true prevents any deferred
// cleanup routines from running, so any code below this line must not be able to fail.
success = true
state := &MountState{
Cmd: cmd,
Stdin: stdin,
stdout: storedStdout,
stderr: storedStderr,
tempDir: tempDir,
root: root,
mountPoint: mountPoint,
oldMask: oldMask,
}
return state
}