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