github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/cmds/core/fusermount/fusermount_test.go (about)

     1  // Copyright 2018-2019 the u-root Authors. All rights reserved
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build linux
     6  // +build linux
     7  
     8  package main
     9  
    10  import (
    11  	"bytes"
    12  	"fmt"
    13  	"net"
    14  	"os"
    15  	"path/filepath"
    16  	"syscall"
    17  	"testing"
    18  
    19  	"github.com/mvdan/u-root-coreutils/pkg/testutil"
    20  	"golang.org/x/sys/unix"
    21  )
    22  
    23  // Until the circleci mess is fixed, skip these tests.
    24  // I give up. We're breaking something in circleci and I'm not sure
    25  // what. This is fine when run from the commandline.
    26  func testArgs(t *testing.T) {
    27  	tmpDir := t.TempDir()
    28  	tdir := filepath.Join(tmpDir, "a/b/c")
    29  	if err := os.MkdirAll(tdir, 0o777); err != nil {
    30  		t.Fatal(err)
    31  	}
    32  	ldir := filepath.Join(tmpDir, "d")
    33  	if err := os.Symlink(tdir, ldir); err != nil {
    34  		t.Fatal(err)
    35  	}
    36  
    37  	tab := []struct {
    38  		n            string
    39  		o            string
    40  		e            int
    41  		a            []string
    42  		env          []string
    43  		requiresRoot bool
    44  	}{
    45  		{n: "badargs", o: help + "\n", e: 1, a: []string{"-zu"}, env: []string{CommFD + "=Nan"}},
    46  		{n: "badpath", o: fmt.Sprintf("resolved path \"%s\" and mountpoint \"%s\" are not the same\n", tdir, ldir), e: 1, a: []string{ldir}, env: []string{CommFD + "=Nan"}},
    47  		{n: "badcfd", o: "_FUSE_COMMFD: strconv.Atoi: parsing \"Nan\": invalid syntax\n", e: 1, a: []string{tdir}, env: []string{CommFD + "=Nan"}},
    48  		{n: "badsock", o: "_FUSE_COMMFD: 5: bad file descriptor\n", e: 1, a: []string{tdir}, env: []string{CommFD + "=5"}, requiresRoot: true},
    49  	}
    50  	skip := len("2018/12/20 16:54:31 ")
    51  
    52  	uid := os.Getuid()
    53  	for _, v := range tab {
    54  		if uid != 0 && v.requiresRoot {
    55  			t.Skipf("test requires root, your uid is %d", uid)
    56  		}
    57  		t.Run(v.n, func(t *testing.T) {
    58  			c := testutil.Command(t, v.a...)
    59  			c.Env = append(c.Env, v.env...)
    60  			c.Stdin = bytes.NewReader([]byte(v.n))
    61  			o, err := c.CombinedOutput()
    62  			// log.Fatal exits differently on circleci and real life
    63  			// Even an explicit os.Exit(1) returns with a 2. WTF?
    64  			if err := testutil.IsExitCode(err, v.e); err != nil {
    65  				t.Logf("Exit codes don't match but we'll ignore that for now")
    66  			}
    67  			if v.e != 0 && err == nil {
    68  				t.Fatalf("Want error, got nil")
    69  			}
    70  			if v.e == 0 && err != nil {
    71  				t.Fatalf("Want no error, got %v", err)
    72  			}
    73  			if len(o) < skip {
    74  				t.Fatalf("Fusermount %v %v: want '%v', got '%v'", v.n, v.a, v.o, o)
    75  			}
    76  			out := string(o[len("2018/12/20 16:54:31 "):])
    77  			if out != v.o {
    78  				t.Fatalf("Fusermount %v %v: want '%v', got '%v'", v.n, v.a, v.o, out)
    79  			}
    80  		})
    81  	}
    82  }
    83  
    84  func TestMount(t *testing.T) {
    85  	if os.Getuid() != 0 {
    86  		t.Skip("Skipping, not root")
    87  	}
    88  	// Get a socketpair to talk on, then spawn the kid
    89  	fds, err := unix.Socketpair(syscall.AF_FILE, syscall.SOCK_STREAM, 0)
    90  	if err != nil {
    91  		t.Fatal(err)
    92  	}
    93  	t.Logf("fds are %v", fds)
    94  
    95  	writeFile := os.NewFile(uintptr(fds[0]), "fusermount-child-writes")
    96  	defer writeFile.Close()
    97  
    98  	readFile := os.NewFile(uintptr(fds[1]), "fusermount-parent-reads")
    99  	defer readFile.Close()
   100  
   101  	tmpDir := t.TempDir()
   102  
   103  	fc, err := net.FileConn(readFile)
   104  	if err != nil {
   105  		t.Fatalf("FileConn from fusermount socket: %v", err)
   106  	}
   107  	defer fc.Close()
   108  
   109  	uc, ok := fc.(*net.UnixConn)
   110  	if !ok {
   111  		t.Fatalf("unexpected FileConn type; expected UnixConn, got %T", fc)
   112  	}
   113  
   114  	c := testutil.Command(t, "-v", tmpDir)
   115  	c.Env = append(c.Env, fmt.Sprintf("_FUSE_COMMFD=%d", fds[0]))
   116  	c.ExtraFiles = []*os.File{writeFile}
   117  	go func() {
   118  		o, err := c.CombinedOutput()
   119  		t.Logf("Running fuse: %v,%v", string(o), err)
   120  	}()
   121  
   122  	buf := make([]byte, 32) // expect 1 byte
   123  	oob := make([]byte, 32) // expect 24 bytes
   124  	_, oobn, _, _, err := uc.ReadMsgUnix(buf, oob)
   125  	if err != nil {
   126  		t.Fatalf("uc.ReadMsgUnix: got %v, want nil", err)
   127  	}
   128  	t.Logf("ReadMsgUnix returns oobn %v, err %v", oobn, err)
   129  	scms, err := syscall.ParseSocketControlMessage(oob[:oobn])
   130  	if err != nil {
   131  		t.Fatalf("syscall.ParseSocketControlMessage(%v): got %v, want nil", oob[:oobn], err)
   132  	}
   133  	t.Logf("syscall.ParseSocketControlMessage(%v): returns %v", oob[:oobn], scms)
   134  	if len(scms) != 1 {
   135  		t.Fatalf("expected 1 SocketControlMessage; got scms = %#v", scms)
   136  	}
   137  	scm := scms[0]
   138  	gotFds, err := syscall.ParseUnixRights(&scm)
   139  	if err != nil {
   140  		t.Fatalf("syscall.ParseUnixRights: %v", err)
   141  	}
   142  	if len(gotFds) != 1 {
   143  		t.Fatalf("wanted 1 fd; got %#v", gotFds)
   144  	}
   145  	f := os.NewFile(uintptr(gotFds[0]), "/dev/fuse")
   146  	t.Logf("file to fuse is %v", f)
   147  	// Now every good program should unmount.
   148  	c = testutil.Command(t, "-v", "-u", tmpDir)
   149  	o, err := c.CombinedOutput()
   150  	t.Logf("Running fuse: %v,%v", string(o), err)
   151  	if err != nil {
   152  		t.Fatal(err)
   153  	}
   154  }
   155  
   156  func TestMain(m *testing.M) {
   157  	testutil.Run(m, main)
   158  }