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  }