github.com/insomniacslk/u-root@v0.0.0-20200717035308-96b791510d76/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  	"io/ioutil"
     9  	"os"
    10  	"path/filepath"
    11  	"reflect"
    12  	"strings"
    13  	"syscall"
    14  	"testing"
    15  
    16  	"github.com/rekby/gpt"
    17  	"github.com/u-root/u-root/pkg/mount"
    18  	"github.com/u-root/u-root/pkg/mount/block"
    19  	"github.com/u-root/u-root/pkg/mount/scuzz"
    20  	"github.com/u-root/u-root/pkg/testutil"
    21  )
    22  
    23  // Assumptions:
    24  //
    25  //   /dev/sda is ./testdata/1MB.ext4_vfat
    26  //	/dev/sda1 is ext4
    27  //	/dev/sda2 is vfat
    28  //
    29  //   /dev/sdb is ./testdata/12Kzeros
    30  //	/dev/sdb1 exists, but is not formatted.
    31  //
    32  //   /dev/sdc is ./testdata/gptdisk
    33  //      /dev/sdc1 exists (EFI system partition), but is not formatted
    34  //      /dev/sdc2 exists (Linux), but is not formatted
    35  
    36  func TestGPT(t *testing.T) {
    37  	testutil.SkipIfNotRoot(t)
    38  
    39  	sdcDisk, err := block.Device("/dev/sdc")
    40  	if err != nil {
    41  		t.Fatal(err)
    42  	}
    43  
    44  	parts, err := sdcDisk.GPTTable()
    45  	if err != nil {
    46  		t.Fatal(err)
    47  	}
    48  	wantParts := []gpt.Partition{
    49  		{FirstLBA: 34, LastLBA: 200},
    50  		{FirstLBA: 201, LastLBA: 366},
    51  	}
    52  	for i, p := range parts.Partitions {
    53  		if !p.IsEmpty() {
    54  			want := wantParts[i]
    55  			if p.FirstLBA != want.FirstLBA {
    56  				t.Errorf("partition %d: got FirstLBA %d want %d", i, p.FirstLBA, want.FirstLBA)
    57  			}
    58  			if p.LastLBA != want.LastLBA {
    59  				t.Errorf("partition %d: got LastLBA %d want %d", i, p.LastLBA, want.LastLBA)
    60  			}
    61  
    62  			t.Logf("partition: %v", p)
    63  		}
    64  	}
    65  }
    66  
    67  func TestFilterPartID(t *testing.T) {
    68  	testutil.SkipIfNotRoot(t)
    69  
    70  	devs, err := block.GetBlockDevices()
    71  	if err != nil {
    72  		t.Fatal(err)
    73  	}
    74  	devs = devs.FilterZeroSize()
    75  
    76  	for _, tt := range []struct {
    77  		guid string
    78  		want block.BlockDevices
    79  	}{
    80  		{
    81  			guid: "C9865081-266C-4A23-A948-C03DAB506198",
    82  			want: block.BlockDevices{
    83  				&block.BlockDev{Name: "sdc2"},
    84  			},
    85  		},
    86  		{
    87  			guid: "c9865081-266c-4a23-a948-c03dab506198",
    88  			want: block.BlockDevices{
    89  				&block.BlockDev{Name: "sdc2"},
    90  			},
    91  		},
    92  		{
    93  			guid: "",
    94  			want: nil,
    95  		},
    96  	} {
    97  		parts := devs.FilterPartID(tt.guid)
    98  		if !reflect.DeepEqual(parts, tt.want) {
    99  			t.Errorf("FilterPartID(%s) = %v, want %v", tt.guid, parts, tt.want)
   100  		}
   101  	}
   102  }
   103  
   104  func TestFilterPartType(t *testing.T) {
   105  	testutil.SkipIfNotRoot(t)
   106  
   107  	devs, err := block.GetBlockDevices()
   108  	if err != nil {
   109  		t.Fatal(err)
   110  	}
   111  	devs = devs.FilterZeroSize()
   112  
   113  	for _, tt := range []struct {
   114  		guid string
   115  		want block.BlockDevices
   116  	}{
   117  		{
   118  			// EFI system partition.
   119  			guid: "C12A7328-F81F-11D2-BA4B-00A0C93EC93B",
   120  			want: block.BlockDevices{
   121  				&block.BlockDev{Name: "sdc1"},
   122  			},
   123  		},
   124  		{
   125  			// EFI system partition. mixed case.
   126  			guid: "c12a7328-f81F-11D2-BA4B-00A0C93ec93B",
   127  			want: block.BlockDevices{
   128  				&block.BlockDev{Name: "sdc1"},
   129  			},
   130  		},
   131  		{
   132  			// This is some random Linux GUID.
   133  			guid: "0FC63DAF-8483-4772-8E79-3D69D8477DE4",
   134  			want: block.BlockDevices{
   135  				&block.BlockDev{Name: "sdc2"},
   136  			},
   137  		},
   138  	} {
   139  		parts := devs.FilterPartType(tt.guid)
   140  		if !reflect.DeepEqual(parts, tt.want) {
   141  			t.Errorf("FilterPartType(%s) = %v, want %v", tt.guid, parts, tt.want)
   142  		}
   143  	}
   144  }
   145  
   146  func TestIdentify(t *testing.T) {
   147  	testutil.SkipIfNotRoot(t)
   148  
   149  	disk, err := scuzz.NewSGDisk("/dev/sda")
   150  	if err != nil {
   151  		t.Fatal(err)
   152  	}
   153  	defer disk.Close()
   154  
   155  	info, err := disk.Identify()
   156  	if err != nil {
   157  		t.Fatal(err)
   158  	}
   159  	t.Logf("Identify(/dev/sda): %v", info)
   160  
   161  	device, err := block.Device("/dev/sda")
   162  	if err != nil {
   163  		t.Fatal(err)
   164  	}
   165  	size, err := device.Size()
   166  	if err != nil {
   167  		t.Fatal(err)
   168  	}
   169  
   170  	if info.NumberSectors != size/512 {
   171  		t.Errorf("Identify(/dev/sda).NumberSectors = %d, want %d", info.NumberSectors, size/512)
   172  	}
   173  }
   174  
   175  func TestBlockDevices(t *testing.T) {
   176  	testutil.SkipIfNotRoot(t)
   177  
   178  	devs, err := block.GetBlockDevices()
   179  	if err != nil {
   180  		t.Fatal(err)
   181  	}
   182  	devs = devs.FilterZeroSize()
   183  
   184  	want := block.BlockDevices{
   185  		&block.BlockDev{Name: "sda"},
   186  		&block.BlockDev{Name: "sda1", FsUUID: "2183ead8-a510-4b3d-9777-19c7090f66d9"},
   187  		&block.BlockDev{Name: "sda2", FsUUID: "ace5-5144"},
   188  		&block.BlockDev{Name: "sdb"},
   189  		&block.BlockDev{Name: "sdb1"},
   190  		&block.BlockDev{Name: "sdc"},
   191  		&block.BlockDev{Name: "sdc1"},
   192  		&block.BlockDev{Name: "sdc2"},
   193  	}
   194  	if !reflect.DeepEqual(devs, want) {
   195  		t.Fatalf("BlockDevices() = \n\t%v want\n\t%v", devs, want)
   196  	}
   197  
   198  	sizes := map[string]uint64{
   199  		"sda":  2048 * 512,
   200  		"sda1": 1024 * 512,
   201  		"sda2": 1023 * 512,
   202  		"sdb":  24 * 512,
   203  		"sdb1": 23 * 512,
   204  		"sdc":  50 * 4096,
   205  		"sdc1": 167 * 512,
   206  		"sdc2": 166 * 512,
   207  	}
   208  	for _, dev := range devs {
   209  		size, err := dev.Size()
   210  		if err != nil {
   211  			t.Errorf("Size(%s) error: %v", dev, err)
   212  		}
   213  		if size != sizes[dev.Name] {
   214  			t.Errorf("Size(%s) = %v, want %v", dev, size, sizes[dev.Name])
   215  		}
   216  	}
   217  
   218  	wantBlkSize := 512
   219  	for _, dev := range devs {
   220  		size, err := dev.BlockSize()
   221  		if err != nil {
   222  			t.Errorf("BlockSize(%s) = %v", dev, err)
   223  		}
   224  		if size != wantBlkSize {
   225  			t.Errorf("BlockSize(%s) = %d, want %d", dev, size, wantBlkSize)
   226  		}
   227  
   228  		pSize, err := dev.PhysicalBlockSize()
   229  		if err != nil {
   230  			t.Errorf("PhysicalBlockSize(%s) = %v", dev, err)
   231  		}
   232  		if pSize != wantBlkSize {
   233  			t.Errorf("PhysicalBlockSize(%s) = %d, want %d", dev, pSize, wantBlkSize)
   234  		}
   235  	}
   236  
   237  	wantRR := map[string]error{
   238  		"sda":  nil,
   239  		"sda1": syscall.EINVAL,
   240  		"sda2": syscall.EINVAL,
   241  		"sdb":  nil,
   242  		"sdb1": syscall.EINVAL,
   243  		"sdc":  nil,
   244  		"sdc1": syscall.EINVAL,
   245  		"sdc2": syscall.EINVAL,
   246  	}
   247  	for _, dev := range devs {
   248  		if err := dev.ReadPartitionTable(); err != wantRR[dev.Name] {
   249  			t.Errorf("ReadPartitionTable(%s) = %v, want %v", dev, err, wantRR[dev.Name])
   250  		}
   251  	}
   252  }
   253  
   254  func TestTryMount(t *testing.T) {
   255  	testutil.SkipIfNotRoot(t)
   256  
   257  	d, err := ioutil.TempDir("", "test-")
   258  	if err != nil {
   259  		t.Fatal(err)
   260  	}
   261  	defer os.RemoveAll(d)
   262  
   263  	sda1 := filepath.Join(d, "sda1")
   264  	if mp, err := mount.TryMount("/dev/sda1", sda1, "", mount.ReadOnly); err != nil {
   265  		t.Errorf("TryMount(/dev/sda1) = %v, want nil", err)
   266  	} else {
   267  		want := &mount.MountPoint{
   268  			Path:   sda1,
   269  			Device: "/dev/sda1",
   270  			FSType: "ext4",
   271  			Flags:  mount.ReadOnly,
   272  		}
   273  		if !reflect.DeepEqual(mp, want) {
   274  			t.Errorf("TryMount(/dev/sda1) = %v, want %v", mp, want)
   275  		}
   276  
   277  		if err := mp.Unmount(0); err != nil {
   278  			t.Errorf("Unmount(%q) = %v, want nil", sda1, err)
   279  		}
   280  	}
   281  
   282  	sda2 := filepath.Join(d, "sda2")
   283  	if mp, err := mount.TryMount("/dev/sda2", sda2, "", mount.ReadOnly); err != nil {
   284  		t.Errorf("TryMount(/dev/sda2) = %v, want nil", err)
   285  	} else {
   286  		want := &mount.MountPoint{
   287  			Path:   sda2,
   288  			Device: "/dev/sda2",
   289  			FSType: "vfat",
   290  			Flags:  mount.ReadOnly,
   291  		}
   292  		if !reflect.DeepEqual(mp, want) {
   293  			t.Errorf("TryMount(/dev/sda2) = %v, want %v", mp, want)
   294  		}
   295  
   296  		if err := mp.Unmount(0); err != nil {
   297  			t.Errorf("Unmount(%q) = %v, want nil", sda1, err)
   298  		}
   299  	}
   300  
   301  	sdb1 := filepath.Join(d, "sdb1")
   302  	if _, err := mount.TryMount("/dev/sdb1", sdb1, "", mount.ReadOnly); !strings.Contains(err.Error(), "no suitable filesystem") {
   303  		t.Errorf("TryMount(/dev/sdb1) = %v, want an error containing 'no suitable filesystem'", err)
   304  	}
   305  
   306  	sdz1 := filepath.Join(d, "sdz1")
   307  	if _, err := mount.TryMount("/dev/sdz1", sdz1, "", mount.ReadOnly); !os.IsNotExist(err) {
   308  		t.Errorf("TryMount(/dev/sdz1) = %v, want an error equivalent to Does Not Exist", err)
   309  	}
   310  }