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 }