github.com/u-root/u-root@v7.0.1-0.20200915234505-ad7babab0a8e+incompatible/pkg/mount/mount_linux_test.go (about) 1 // Copyright 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 package mount_test 6 7 import ( 8 "fmt" 9 "io/ioutil" 10 "log" 11 "os" 12 "path/filepath" 13 "reflect" 14 "strings" 15 "syscall" 16 "testing" 17 18 "github.com/rekby/gpt" 19 "github.com/u-root/u-root/pkg/mount" 20 "github.com/u-root/u-root/pkg/mount/block" 21 "github.com/u-root/u-root/pkg/pci" 22 "github.com/u-root/u-root/pkg/testutil" 23 ) 24 25 // Assumptions: 26 // 27 // /dev/sda is ./testdata/1MB.ext4_vfat 28 // /dev/sda1 is ext4 29 // /dev/sda2 is vfat 30 // 31 // /dev/sdb is ./testdata/12Kzeros 32 // /dev/sdb1 exists, but is not formatted. 33 // 34 // /dev/sdc is ./testdata/gptdisk 35 // /dev/sdc1 exists (EFI system partition), but is not formatted 36 // /dev/sdc2 exists (Linux), but is not formatted 37 // 38 // ARM tests will load drives as virtio-blk devices (/dev/vd*) 39 40 func TestGPT(t *testing.T) { 41 testutil.SkipIfNotRoot(t) 42 43 devpath := fmt.Sprintf("/dev/%sc", getDevicePrefix()) 44 45 sdcDisk, err := block.Device(devpath) 46 if err != nil { 47 t.Fatal(err) 48 } 49 50 parts, err := sdcDisk.GPTTable() 51 if err != nil { 52 t.Fatal(err) 53 } 54 wantParts := []gpt.Partition{ 55 {FirstLBA: 34, LastLBA: 200}, 56 {FirstLBA: 201, LastLBA: 366}, 57 } 58 for i, p := range parts.Partitions { 59 if !p.IsEmpty() { 60 want := wantParts[i] 61 if p.FirstLBA != want.FirstLBA { 62 t.Errorf("partition %d: got FirstLBA %d want %d", i, p.FirstLBA, want.FirstLBA) 63 } 64 if p.LastLBA != want.LastLBA { 65 t.Errorf("partition %d: got LastLBA %d want %d", i, p.LastLBA, want.LastLBA) 66 } 67 68 t.Logf("partition: %v", p) 69 } 70 } 71 } 72 73 func TestFilterPartID(t *testing.T) { 74 testutil.SkipIfNotRoot(t) 75 76 devname := fmt.Sprintf("%sc2", getDevicePrefix()) 77 78 devs, err := block.GetBlockDevices() 79 if err != nil { 80 t.Fatal(err) 81 } 82 devs = devs.FilterZeroSize() 83 84 for _, tt := range []struct { 85 guid string 86 want block.BlockDevices 87 }{ 88 { 89 guid: "C9865081-266C-4A23-A948-C03DAB506198", 90 want: block.BlockDevices{ 91 &block.BlockDev{Name: devname}, 92 }, 93 }, 94 { 95 guid: "c9865081-266c-4a23-a948-c03dab506198", 96 want: block.BlockDevices{ 97 &block.BlockDev{Name: devname}, 98 }, 99 }, 100 { 101 guid: "", 102 want: nil, 103 }, 104 } { 105 parts := devs.FilterPartID(tt.guid) 106 if !reflect.DeepEqual(parts, tt.want) { 107 t.Errorf("FilterPartID(%s) = %v, want %v", tt.guid, parts, tt.want) 108 } 109 } 110 } 111 112 func TestFilterPartType(t *testing.T) { 113 testutil.SkipIfNotRoot(t) 114 115 prefix := getDevicePrefix() 116 117 devs, err := block.GetBlockDevices() 118 if err != nil { 119 t.Fatal(err) 120 } 121 devs = devs.FilterZeroSize() 122 123 for _, tt := range []struct { 124 guid string 125 want block.BlockDevices 126 }{ 127 { 128 // EFI system partition. 129 guid: "C12A7328-F81F-11D2-BA4B-00A0C93EC93B", 130 want: block.BlockDevices{ 131 &block.BlockDev{Name: prefix + "c1"}, 132 }, 133 }, 134 { 135 // EFI system partition. mixed case. 136 guid: "c12a7328-f81F-11D2-BA4B-00A0C93ec93B", 137 want: block.BlockDevices{ 138 &block.BlockDev{Name: prefix + "c1"}, 139 }, 140 }, 141 { 142 // This is some random Linux GUID. 143 guid: "0FC63DAF-8483-4772-8E79-3D69D8477DE4", 144 want: block.BlockDevices{ 145 &block.BlockDev{Name: prefix + "c2"}, 146 }, 147 }, 148 } { 149 parts := devs.FilterPartType(tt.guid) 150 if !reflect.DeepEqual(parts, tt.want) { 151 t.Errorf("FilterPartType(%s) = %v, want %v", tt.guid, parts, tt.want) 152 } 153 } 154 } 155 156 func TestFilterBlockPCI(t *testing.T) { 157 testutil.SkipIfNotRoot(t) 158 159 prefix := getDevicePrefix() 160 161 devs, err := block.GetBlockDevices() 162 if err != nil { 163 t.Fatal(err) 164 } 165 devs = devs.FilterZeroSize() 166 167 // Check that NVME devices are present. 168 want := block.BlockDevices{ 169 &block.BlockDev{Name: "nvme0n1"}, 170 &block.BlockDev{Name: "nvme0n1p1"}, 171 &block.BlockDev{Name: "nvme0n1p2"}, 172 &block.BlockDev{Name: prefix + "a"}, 173 &block.BlockDev{Name: prefix + "a1", FsUUID: "2183ead8-a510-4b3d-9777-19c7090f66d9"}, 174 &block.BlockDev{Name: prefix + "a2", FsUUID: "ace5-5144"}, 175 &block.BlockDev{Name: prefix + "b"}, 176 &block.BlockDev{Name: prefix + "b1"}, 177 &block.BlockDev{Name: prefix + "c"}, 178 &block.BlockDev{Name: prefix + "c1"}, 179 &block.BlockDev{Name: prefix + "c2"}, 180 } 181 if !reflect.DeepEqual(devs, want) { 182 t.Fatalf("BlockDevices() = \n\t%v want\n\t%v", devs, want) 183 } 184 185 p := &pci.PCI{Vendor: "0x8086", Device: "0x5845"} 186 pl := pci.Devices{p} 187 188 block.Debug = log.Printf 189 devs = devs.FilterBlockPCI(pl) 190 191 want = block.BlockDevices{ 192 &block.BlockDev{Name: prefix + "a"}, 193 &block.BlockDev{Name: prefix + "a1", FsUUID: "2183ead8-a510-4b3d-9777-19c7090f66d9"}, 194 &block.BlockDev{Name: prefix + "a2", FsUUID: "ace5-5144"}, 195 &block.BlockDev{Name: prefix + "b"}, 196 &block.BlockDev{Name: prefix + "b1"}, 197 &block.BlockDev{Name: prefix + "c"}, 198 &block.BlockDev{Name: prefix + "c1"}, 199 &block.BlockDev{Name: prefix + "c2"}, 200 } 201 if !reflect.DeepEqual(devs, want) { 202 t.Fatalf("BlockDevices() = \n\t%v want\n\t%v", devs, want) 203 } 204 } 205 206 func TestFilterBlockPCIString(t *testing.T) { 207 testutil.SkipIfNotRoot(t) 208 209 prefix := getDevicePrefix() 210 211 devs, err := block.GetBlockDevices() 212 if err != nil { 213 t.Fatal(err) 214 } 215 devs = devs.FilterZeroSize() 216 217 // Check that NVME devices are present. 218 want := block.BlockDevices{ 219 &block.BlockDev{Name: "nvme0n1"}, 220 &block.BlockDev{Name: "nvme0n1p1"}, 221 &block.BlockDev{Name: "nvme0n1p2"}, 222 &block.BlockDev{Name: prefix + "a"}, 223 &block.BlockDev{Name: prefix + "a1", FsUUID: "2183ead8-a510-4b3d-9777-19c7090f66d9"}, 224 &block.BlockDev{Name: prefix + "a2", FsUUID: "ace5-5144"}, 225 &block.BlockDev{Name: prefix + "b"}, 226 &block.BlockDev{Name: prefix + "b1"}, 227 &block.BlockDev{Name: prefix + "c"}, 228 &block.BlockDev{Name: prefix + "c1"}, 229 &block.BlockDev{Name: prefix + "c2"}, 230 } 231 if !reflect.DeepEqual(devs, want) { 232 t.Fatalf("BlockDevices() = \n\t%v want\n\t%v", devs, want) 233 } 234 235 block.Debug = log.Printf 236 devs, err = devs.FilterBlockPCIString("0x8086:0x5845") 237 if err != nil { 238 t.Fatal(err) 239 } 240 241 want = block.BlockDevices{ 242 &block.BlockDev{Name: prefix + "a"}, 243 &block.BlockDev{Name: prefix + "a1", FsUUID: "2183ead8-a510-4b3d-9777-19c7090f66d9"}, 244 &block.BlockDev{Name: prefix + "a2", FsUUID: "ace5-5144"}, 245 &block.BlockDev{Name: prefix + "b"}, 246 &block.BlockDev{Name: prefix + "b1"}, 247 &block.BlockDev{Name: prefix + "c"}, 248 &block.BlockDev{Name: prefix + "c1"}, 249 &block.BlockDev{Name: prefix + "c2"}, 250 } 251 if !reflect.DeepEqual(devs, want) { 252 t.Fatalf("BlockDevices() = \n\t%v want\n\t%v", devs, want) 253 } 254 } 255 256 func TestBlockDevices(t *testing.T) { 257 testutil.SkipIfNotRoot(t) 258 259 prefix := getDevicePrefix() 260 261 devs, err := block.GetBlockDevices() 262 if err != nil { 263 t.Fatal(err) 264 } 265 devs = devs.FilterZeroSize() 266 267 want := block.BlockDevices{ 268 &block.BlockDev{Name: "nvme0n1"}, 269 &block.BlockDev{Name: "nvme0n1p1"}, 270 &block.BlockDev{Name: "nvme0n1p2"}, 271 &block.BlockDev{Name: prefix + "a"}, 272 &block.BlockDev{Name: prefix + "a1", FsUUID: "2183ead8-a510-4b3d-9777-19c7090f66d9"}, 273 &block.BlockDev{Name: prefix + "a2", FsUUID: "ace5-5144"}, 274 &block.BlockDev{Name: prefix + "b"}, 275 &block.BlockDev{Name: prefix + "b1"}, 276 &block.BlockDev{Name: prefix + "c"}, 277 &block.BlockDev{Name: prefix + "c1"}, 278 &block.BlockDev{Name: prefix + "c2"}, 279 } 280 if !reflect.DeepEqual(devs, want) { 281 t.Fatalf("BlockDevices() = \n\t%v want\n\t%v", devs, want) 282 } 283 284 sizes := map[string]uint64{ 285 "nvme0n1": 50 * 4096, 286 "nvme0n1p1": 167 * 512, 287 "nvme0n1p2": 166 * 512, 288 prefix + "a": 2048 * 512, 289 prefix + "a1": 1024 * 512, 290 prefix + "a2": 1023 * 512, 291 prefix + "b": 24 * 512, 292 prefix + "b1": 23 * 512, 293 prefix + "c": 50 * 4096, 294 prefix + "c1": 167 * 512, 295 prefix + "c2": 166 * 512, 296 } 297 for _, dev := range devs { 298 size, err := dev.Size() 299 if err != nil { 300 t.Errorf("Size(%s) error: %v", dev, err) 301 } 302 if size != sizes[dev.Name] { 303 t.Errorf("Size(%s) = %v, want %v", dev, size, sizes[dev.Name]) 304 } 305 } 306 307 wantBlkSize := 512 308 for _, dev := range devs { 309 size, err := dev.BlockSize() 310 if err != nil { 311 t.Errorf("BlockSize(%s) = %v", dev, err) 312 } 313 if size != wantBlkSize { 314 t.Errorf("BlockSize(%s) = %d, want %d", dev, size, wantBlkSize) 315 } 316 317 pSize, err := dev.PhysicalBlockSize() 318 if err != nil { 319 t.Errorf("PhysicalBlockSize(%s) = %v", dev, err) 320 } 321 if pSize != wantBlkSize { 322 t.Errorf("PhysicalBlockSize(%s) = %d, want %d", dev, pSize, wantBlkSize) 323 } 324 } 325 326 wantRR := map[string]error{ 327 "nvme0n1": nil, 328 "nvme0n1p1": syscall.EINVAL, 329 "nvme0n1p2": syscall.EINVAL, 330 prefix + "a": nil, 331 prefix + "a1": syscall.EINVAL, 332 prefix + "a2": syscall.EINVAL, 333 prefix + "b": nil, 334 prefix + "b1": syscall.EINVAL, 335 prefix + "c": nil, 336 prefix + "c1": syscall.EINVAL, 337 prefix + "c2": syscall.EINVAL, 338 } 339 for _, dev := range devs { 340 if err := dev.ReadPartitionTable(); err != wantRR[dev.Name] { 341 t.Errorf("ReadPartitionTable(%s) = %v, want %v", dev, err, wantRR[dev.Name]) 342 } 343 } 344 } 345 346 func TestTryMount(t *testing.T) { 347 testutil.SkipIfNotRoot(t) 348 349 prefix := getDevicePrefix() 350 351 d, err := ioutil.TempDir("", "test-") 352 if err != nil { 353 t.Fatal(err) 354 } 355 defer os.RemoveAll(d) 356 357 sda1 := filepath.Join(d, prefix+"a1") 358 deva1 := fmt.Sprintf("/dev/%sa1", prefix) 359 if mp, err := mount.TryMount(deva1, sda1, "", mount.ReadOnly); err != nil { 360 t.Errorf("TryMount(%s) = %v, want nil", deva1, err) 361 } else { 362 want := &mount.MountPoint{ 363 Path: sda1, 364 Device: deva1, 365 FSType: "ext4", 366 Flags: mount.ReadOnly, 367 } 368 if !reflect.DeepEqual(mp, want) { 369 t.Errorf("TryMount(%s) = %v, want %v", deva1, mp, want) 370 } 371 372 if err := mp.Unmount(0); err != nil { 373 t.Errorf("Unmount(%q) = %v, want nil", sda1, err) 374 } 375 } 376 377 sda2 := filepath.Join(d, prefix+"a2") 378 deva2 := fmt.Sprintf("/dev/%sa2", prefix) 379 if mp, err := mount.TryMount(deva2, sda2, "", mount.ReadOnly); err != nil { 380 t.Errorf("TryMount(%s) = %v, want nil", deva2, err) 381 } else { 382 want := &mount.MountPoint{ 383 Path: sda2, 384 Device: deva2, 385 FSType: "vfat", 386 Flags: mount.ReadOnly, 387 } 388 if !reflect.DeepEqual(mp, want) { 389 t.Errorf("TryMount(%s) = %v, want %v", deva2, mp, want) 390 } 391 392 if err := mp.Unmount(0); err != nil { 393 t.Errorf("Unmount(%q) = %v, want nil", sda1, err) 394 } 395 } 396 397 sdb1 := filepath.Join(d, prefix+"b1") 398 devb1 := fmt.Sprintf("/dev/%sb1", prefix) 399 if _, err := mount.TryMount(devb1, sdb1, "", mount.ReadOnly); !strings.Contains(err.Error(), "no suitable filesystem") { 400 t.Errorf("TryMount(%s) = %v, want an error containing 'no suitable filesystem'", devb1, err) 401 } 402 403 sdz1 := filepath.Join(d, prefix+"z1") 404 devz1 := fmt.Sprintf("/dev/%sz1", prefix) 405 if _, err := mount.TryMount(devz1, sdz1, "", mount.ReadOnly); !os.IsNotExist(err) { 406 t.Errorf("TryMount(%s) = %v, want an error equivalent to Does Not Exist", devz1, err) 407 } 408 } 409 410 func getDevicePrefix() string { 411 if _, err := os.Stat("/dev/sdc"); err != nil { 412 return "vd" 413 } 414 return "sd" 415 }