github.com/containerd/containerd@v22.0.0-20200918172823-438c87b8e050+incompatible/sys/mount_linux_test.go (about) 1 /* 2 Copyright The containerd Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package sys 18 19 import ( 20 "io/ioutil" 21 "os" 22 "path/filepath" 23 "syscall" 24 "testing" 25 "time" 26 27 "github.com/containerd/continuity/fs/fstest" 28 "github.com/pkg/errors" 29 "golang.org/x/sys/unix" 30 ) 31 32 type fMountatCaseFunc func(t *testing.T, root string) 33 34 func TestFMountat(t *testing.T) { 35 if RunningUnprivileged() { 36 t.Skip("Needs to be run as root") 37 return 38 } 39 40 t.Run("Normal", makeTestForFMountat(testFMountatNormal)) 41 t.Run("ChdirWithFileFd", makeTestForFMountat(testFMountatWithFileFd)) 42 t.Run("MountWithInvalidSource", makeTestForFMountat(testFMountatWithInvalidSource)) 43 } 44 45 func makeTestForFMountat(fn fMountatCaseFunc) func(t *testing.T) { 46 return func(t *testing.T) { 47 t.Parallel() 48 49 suiteDir, err := ioutil.TempDir("", "fmountat-test-") 50 if err != nil { 51 t.Fatal(err) 52 } 53 defer os.RemoveAll(suiteDir) 54 55 fn(t, suiteDir) 56 } 57 } 58 59 func testFMountatNormal(t *testing.T, root string) { 60 expectedContent := "bye re-exec!\n" 61 apply := fstest.Apply( 62 fstest.CreateFile("/hi", []byte(expectedContent), 0777), 63 ) 64 65 workdir := filepath.Join(root, "work") 66 if err := os.MkdirAll(workdir, 0777); err != nil { 67 t.Fatalf("failed to create dir(%s): %+v", workdir, err) 68 } 69 70 if err := apply.Apply(workdir); err != nil { 71 t.Fatalf("failed to prepare source dir: %+v", err) 72 } 73 74 atdir := filepath.Join(root, "at") 75 if err := os.MkdirAll(atdir, 0777); err != nil { 76 t.Fatalf("failed to create working dir(%s): %+v", atdir, err) 77 } 78 79 fsdir := filepath.Join(atdir, "fs") 80 if err := os.MkdirAll(fsdir, 0777); err != nil { 81 t.Fatalf("failed to create mount point dir(%s): %+v", fsdir, err) 82 } 83 84 f, err := os.Open(atdir) 85 if err != nil { 86 t.Fatalf("failed to open dir(%s): %+v", atdir, err) 87 } 88 defer f.Close() 89 90 // mount work to fs 91 if err = FMountat(f.Fd(), workdir, "fs", "bind", unix.MS_BIND|unix.MS_RDONLY, ""); err != nil { 92 t.Fatalf("expected no error here, but got error: %+v", err) 93 } 94 defer umount(t, fsdir) 95 96 // check hi file 97 content, err := ioutil.ReadFile(filepath.Join(fsdir, "hi")) 98 if err != nil { 99 t.Fatalf("failed to read file: %+v", err) 100 } 101 if got := string(content); got != expectedContent { 102 t.Fatalf("expected to get(%v), but got(%v)", expectedContent, got) 103 } 104 105 // check the working directory 106 cwd, err := os.Getwd() 107 if err != nil { 108 t.Fatalf("failed to get current working dir: %+v", err) 109 } 110 111 if cwd == atdir { 112 t.Fatal("should not change the current working directory") 113 } 114 } 115 116 func testFMountatWithFileFd(t *testing.T, root string) { 117 // not a directory 118 expectedErr := syscall.Errno(20) 119 120 emptyFile := filepath.Join(root, "emptyFile") 121 f, err := os.Create(emptyFile) 122 if err != nil { 123 t.Fatalf("failed to create file(%s): %+v", emptyFile, err) 124 } 125 defer f.Close() 126 127 err = FMountat(f.Fd(), filepath.Join(root, "empty"), filepath.Join(root, "work"), "", 0, "") 128 if !errors.Is(err, expectedErr) { 129 t.Fatalf("expected error %v, but got %v", expectedErr, errors.Cause(err)) 130 } 131 } 132 133 func testFMountatWithInvalidSource(t *testing.T, root string) { 134 // no such file or directory 135 expectedErr := syscall.Errno(2) 136 137 atdir := filepath.Join(root, "at") 138 if err := os.MkdirAll(atdir, 0777); err != nil { 139 t.Fatalf("failed to create dir(%s): %+v", atdir, err) 140 } 141 142 f, err := os.Open(root) 143 if err != nil { 144 t.Fatalf("failed to open dir(%s): %+v", atdir, err) 145 } 146 defer f.Close() 147 148 err = FMountat(f.Fd(), filepath.Join(root, "oops"), "at", "bind", unix.MS_BIND, "") 149 if !errors.Is(err, expectedErr) { 150 t.Fatalf("expected error %v, but got %v", expectedErr, err) 151 } 152 } 153 154 func umount(t *testing.T, target string) { 155 for i := 0; i < 50; i++ { 156 if err := unix.Unmount(target, unix.MNT_DETACH); err != nil { 157 switch err { 158 case unix.EBUSY: 159 time.Sleep(50 * time.Millisecond) 160 continue 161 case unix.EINVAL: 162 return 163 default: 164 continue 165 } 166 } 167 } 168 t.Fatalf("failed to unmount target %s", target) 169 }