github.com/rigado/snapd@v2.42.5-go-mod+incompatible/gadget/device_test.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2019 Canonical Ltd
     5   *
     6   * This program is free software: you can redistribute it and/or modify
     7   * it under the terms of the GNU General Public License version 3 as
     8   * published by the Free Software Foundation.
     9   *
    10   * This program is distributed in the hope that it will be useful,
    11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13   * GNU General Public License for more details.
    14   *
    15   * You should have received a copy of the GNU General Public License
    16   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17   *
    18   */
    19  
    20  package gadget_test
    21  
    22  import (
    23  	"errors"
    24  	"io/ioutil"
    25  	"os"
    26  	"path/filepath"
    27  	"strings"
    28  
    29  	. "gopkg.in/check.v1"
    30  
    31  	"github.com/snapcore/snapd/dirs"
    32  	"github.com/snapcore/snapd/gadget"
    33  	"github.com/snapcore/snapd/osutil"
    34  )
    35  
    36  type deviceSuite struct {
    37  	dir string
    38  }
    39  
    40  var _ = Suite(&deviceSuite{})
    41  
    42  func (d *deviceSuite) SetUpTest(c *C) {
    43  	d.dir = c.MkDir()
    44  	dirs.SetRootDir(d.dir)
    45  
    46  	err := os.MkdirAll(filepath.Join(d.dir, "/dev/disk/by-label"), 0755)
    47  	c.Assert(err, IsNil)
    48  	err = os.MkdirAll(filepath.Join(d.dir, "/dev/disk/by-partlabel"), 0755)
    49  	c.Assert(err, IsNil)
    50  	err = ioutil.WriteFile(filepath.Join(d.dir, "/dev/fakedevice"), []byte(""), 0644)
    51  	c.Assert(err, IsNil)
    52  }
    53  
    54  func (d *deviceSuite) TearDownTest(c *C) {
    55  	dirs.SetRootDir("/")
    56  }
    57  
    58  func (d *deviceSuite) setUpWritableFallback(c *C, mountInfo string) {
    59  	// setup everything for 'writable'
    60  	err := ioutil.WriteFile(filepath.Join(d.dir, "/dev/fakedevice0p1"), []byte(""), 0644)
    61  	c.Assert(err, IsNil)
    62  	err = os.Symlink("../../fakedevice0p1", filepath.Join(d.dir, "/dev/disk/by-label/writable"))
    63  	c.Assert(err, IsNil)
    64  	// make parent device
    65  	err = ioutil.WriteFile(filepath.Join(d.dir, "/dev/fakedevice0"), []byte(""), 0644)
    66  	c.Assert(err, IsNil)
    67  	// and fake /sys/block structure
    68  	err = os.MkdirAll(filepath.Join(d.dir, "/sys/block/fakedevice0/fakedevice0p1"), 0755)
    69  	c.Assert(err, IsNil)
    70  
    71  	mockProcSelfFilesystem(c, d.dir, mountInfo)
    72  }
    73  
    74  func (d *deviceSuite) TestDeviceFindByStructureName(c *C) {
    75  	names := []struct {
    76  		escaped   string
    77  		structure string
    78  	}{
    79  		{"foo", "foo"},
    80  		{"123", "123"},
    81  		{"foo\\x20bar", "foo bar"},
    82  		{"foo#bar", "foo#bar"},
    83  		{"Новый_том", "Новый_том"},
    84  		{`pinkié\x20pie`, `pinkié pie`},
    85  	}
    86  	for _, name := range names {
    87  		err := os.Symlink(filepath.Join(d.dir, "/dev/fakedevice"), filepath.Join(d.dir, "/dev/disk/by-partlabel", name.escaped))
    88  		c.Assert(err, IsNil)
    89  	}
    90  
    91  	for _, tc := range names {
    92  		c.Logf("trying: %q", tc)
    93  		found, err := gadget.FindDeviceForStructure(&gadget.LaidOutStructure{
    94  			VolumeStructure: &gadget.VolumeStructure{Name: tc.structure},
    95  		})
    96  		c.Check(err, IsNil)
    97  		c.Check(found, Equals, filepath.Join(d.dir, "/dev/fakedevice"))
    98  	}
    99  }
   100  
   101  func (d *deviceSuite) TestDeviceFindRelativeSymlink(c *C) {
   102  	err := os.Symlink("../../fakedevice", filepath.Join(d.dir, "/dev/disk/by-partlabel/relative"))
   103  	c.Assert(err, IsNil)
   104  
   105  	found, err := gadget.FindDeviceForStructure(&gadget.LaidOutStructure{
   106  		VolumeStructure: &gadget.VolumeStructure{Name: "relative"},
   107  	})
   108  	c.Check(err, IsNil)
   109  	c.Check(found, Equals, filepath.Join(d.dir, "/dev/fakedevice"))
   110  }
   111  
   112  func (d *deviceSuite) TestDeviceFindByFilesystemLabel(c *C) {
   113  	names := []struct {
   114  		escaped   string
   115  		structure string
   116  	}{
   117  		{"foo", "foo"},
   118  		{"123", "123"},
   119  		{`foo\x20bar`, "foo bar"},
   120  		{"foo#bar", "foo#bar"},
   121  		{"Новый_том", "Новый_том"},
   122  		{`pinkié\x20pie`, `pinkié pie`},
   123  	}
   124  	for _, name := range names {
   125  		err := os.Symlink(filepath.Join(d.dir, "/dev/fakedevice"), filepath.Join(d.dir, "/dev/disk/by-label", name.escaped))
   126  		c.Assert(err, IsNil)
   127  	}
   128  
   129  	for _, tc := range names {
   130  		c.Logf("trying: %q", tc)
   131  		found, err := gadget.FindDeviceForStructure(&gadget.LaidOutStructure{
   132  			VolumeStructure: &gadget.VolumeStructure{Label: tc.structure},
   133  		})
   134  		c.Check(err, IsNil)
   135  		c.Check(found, Equals, filepath.Join(d.dir, "/dev/fakedevice"))
   136  	}
   137  }
   138  
   139  func (d *deviceSuite) TestDeviceFindChecksPartlabelAndFilesystemLabelHappy(c *C) {
   140  	fakedevice := filepath.Join(d.dir, "/dev/fakedevice")
   141  	err := os.Symlink(fakedevice, filepath.Join(d.dir, "/dev/disk/by-label/foo"))
   142  	c.Assert(err, IsNil)
   143  
   144  	err = os.Symlink(fakedevice, filepath.Join(d.dir, "/dev/disk/by-partlabel/bar"))
   145  	c.Assert(err, IsNil)
   146  
   147  	found, err := gadget.FindDeviceForStructure(&gadget.LaidOutStructure{
   148  		VolumeStructure: &gadget.VolumeStructure{
   149  			Name:  "bar",
   150  			Label: "foo",
   151  		},
   152  	})
   153  	c.Check(err, IsNil)
   154  	c.Check(found, Equals, filepath.Join(d.dir, "/dev/fakedevice"))
   155  }
   156  
   157  func (d *deviceSuite) TestDeviceFindChecksPartlabelAndFilesystemLabelMismatch(c *C) {
   158  	fakedevice := filepath.Join(d.dir, "/dev/fakedevice")
   159  	err := os.Symlink(fakedevice, filepath.Join(d.dir, "/dev/disk/by-label/foo"))
   160  	c.Assert(err, IsNil)
   161  
   162  	// partlabel of the structure points to a different device
   163  	fakedeviceOther := filepath.Join(d.dir, "/dev/fakedevice-other")
   164  	err = ioutil.WriteFile(fakedeviceOther, []byte(""), 0644)
   165  	c.Assert(err, IsNil)
   166  	err = os.Symlink(fakedeviceOther, filepath.Join(d.dir, "/dev/disk/by-partlabel/bar"))
   167  	c.Assert(err, IsNil)
   168  
   169  	found, err := gadget.FindDeviceForStructure(&gadget.LaidOutStructure{
   170  		VolumeStructure: &gadget.VolumeStructure{
   171  			Name:  "bar",
   172  			Label: "foo",
   173  		},
   174  	})
   175  	c.Check(err, ErrorMatches, `conflicting device match, ".*/by-label/foo" points to ".*/fakedevice", previous match ".*/by-partlabel/bar" points to ".*/fakedevice-other"`)
   176  	c.Check(found, Equals, "")
   177  }
   178  
   179  func (d *deviceSuite) TestDeviceFindNotFound(c *C) {
   180  	found, err := gadget.FindDeviceForStructure(&gadget.LaidOutStructure{
   181  		VolumeStructure: &gadget.VolumeStructure{
   182  			Name:  "bar",
   183  			Label: "foo",
   184  		},
   185  	})
   186  	c.Check(err, ErrorMatches, `device not found`)
   187  	c.Check(found, Equals, "")
   188  }
   189  
   190  func (d *deviceSuite) TestDeviceFindNotFoundEmpty(c *C) {
   191  	// neither name nor filesystem label set
   192  	found, err := gadget.FindDeviceForStructure(&gadget.LaidOutStructure{
   193  		VolumeStructure: &gadget.VolumeStructure{
   194  			Name:  "",
   195  			Label: "",
   196  		},
   197  	})
   198  	c.Check(err, ErrorMatches, `device not found`)
   199  	c.Check(found, Equals, "")
   200  }
   201  
   202  func (d *deviceSuite) TestDeviceFindNotFoundSymlinkPointsNowhere(c *C) {
   203  	fakedevice := filepath.Join(d.dir, "/dev/fakedevice-not-found")
   204  	err := os.Symlink(fakedevice, filepath.Join(d.dir, "/dev/disk/by-label/foo"))
   205  	c.Assert(err, IsNil)
   206  
   207  	found, err := gadget.FindDeviceForStructure(&gadget.LaidOutStructure{
   208  		VolumeStructure: &gadget.VolumeStructure{
   209  			Label: "foo",
   210  		},
   211  	})
   212  	c.Check(err, ErrorMatches, `device not found`)
   213  	c.Check(found, Equals, "")
   214  }
   215  
   216  func (d *deviceSuite) TestDeviceFindNotFoundNotASymlink(c *C) {
   217  	err := ioutil.WriteFile(filepath.Join(d.dir, "/dev/disk/by-label/foo"), nil, 0644)
   218  	c.Assert(err, IsNil)
   219  
   220  	found, err := gadget.FindDeviceForStructure(&gadget.LaidOutStructure{
   221  		VolumeStructure: &gadget.VolumeStructure{
   222  			Label: "foo",
   223  		},
   224  	})
   225  	c.Check(err, ErrorMatches, `candidate .*/dev/disk/by-label/foo is not a symlink`)
   226  	c.Check(found, Equals, "")
   227  }
   228  
   229  func (d *deviceSuite) TestDeviceFindBadEvalSymlinks(c *C) {
   230  	fakedevice := filepath.Join(d.dir, "/dev/fakedevice")
   231  	fooSymlink := filepath.Join(d.dir, "/dev/disk/by-label/foo")
   232  	err := os.Symlink(fakedevice, fooSymlink)
   233  	c.Assert(err, IsNil)
   234  
   235  	restore := gadget.MockEvalSymlinks(func(p string) (string, error) {
   236  		c.Assert(p, Equals, fooSymlink)
   237  		return "", errors.New("failed")
   238  	})
   239  	defer restore()
   240  
   241  	found, err := gadget.FindDeviceForStructure(&gadget.LaidOutStructure{
   242  		VolumeStructure: &gadget.VolumeStructure{
   243  			Label: "foo",
   244  		},
   245  	})
   246  	c.Check(err, ErrorMatches, `cannot read device link: failed`)
   247  	c.Check(found, Equals, "")
   248  }
   249  
   250  var writableMountInfo = `26 27 8:3 / /writable rw,relatime shared:7 - ext4 /dev/fakedevice0p1 rw,data=ordered`
   251  
   252  func (d *deviceSuite) TestDeviceFindFallbackNotFoundNoWritable(c *C) {
   253  	badMountInfo := `26 27 8:3 / /not-writable rw,relatime shared:7 - ext4 /dev/fakedevice0p1 rw,data=ordered`
   254  
   255  	mockProcSelfFilesystem(c, d.dir, badMountInfo)
   256  
   257  	found, offs, err := gadget.FindDeviceForStructureWithFallback(&gadget.LaidOutStructure{
   258  		VolumeStructure: &gadget.VolumeStructure{
   259  			Type: "bare",
   260  		},
   261  		StartOffset: 123,
   262  	})
   263  	c.Check(err, ErrorMatches, `device not found`)
   264  	c.Check(found, Equals, "")
   265  	c.Check(offs, Equals, gadget.Size(0))
   266  }
   267  
   268  func (d *deviceSuite) TestDeviceFindFallbackBadWritable(c *C) {
   269  	mockProcSelfFilesystem(c, d.dir, writableMountInfo)
   270  
   271  	ps := &gadget.LaidOutStructure{
   272  		VolumeStructure: &gadget.VolumeStructure{
   273  			Type: "bare",
   274  		},
   275  		StartOffset: 123,
   276  	}
   277  
   278  	found, offs, err := gadget.FindDeviceForStructureWithFallback(ps)
   279  	c.Check(err, ErrorMatches, `unexpected number of matches \(0\) for /sys/block/\*/fakedevice0p1`)
   280  	c.Check(found, Equals, "")
   281  	c.Check(offs, Equals, gadget.Size(0))
   282  
   283  	err = os.MkdirAll(filepath.Join(d.dir, "/sys/block/fakedevice0/fakedevice0p1"), 0755)
   284  	c.Assert(err, IsNil)
   285  
   286  	found, offs, err = gadget.FindDeviceForStructureWithFallback(ps)
   287  	c.Check(err, ErrorMatches, `device .*/dev/fakedevice0 does not exist`)
   288  	c.Check(found, Equals, "")
   289  	c.Check(offs, Equals, gadget.Size(0))
   290  }
   291  
   292  func (d *deviceSuite) TestDeviceFindFallbackHappyWritable(c *C) {
   293  	d.setUpWritableFallback(c, writableMountInfo)
   294  
   295  	psJustBare := &gadget.LaidOutStructure{
   296  		VolumeStructure: &gadget.VolumeStructure{
   297  			Type: "bare",
   298  		},
   299  		StartOffset: 123,
   300  	}
   301  	psBareWithName := &gadget.LaidOutStructure{
   302  		VolumeStructure: &gadget.VolumeStructure{
   303  			Type: "bare",
   304  			Name: "foo",
   305  		},
   306  		StartOffset: 123,
   307  	}
   308  	psNoName := &gadget.LaidOutStructure{
   309  		VolumeStructure: &gadget.VolumeStructure{},
   310  		StartOffset:     123,
   311  	}
   312  
   313  	for _, ps := range []*gadget.LaidOutStructure{psJustBare, psBareWithName, psNoName} {
   314  		found, offs, err := gadget.FindDeviceForStructureWithFallback(ps)
   315  		c.Check(err, IsNil)
   316  		c.Check(found, Equals, filepath.Join(d.dir, "/dev/fakedevice0"))
   317  		c.Check(offs, Equals, gadget.Size(123))
   318  	}
   319  }
   320  
   321  func (d *deviceSuite) TestDeviceFindFallbackNotForNamedWritable(c *C) {
   322  	d.setUpWritableFallback(c, writableMountInfo)
   323  
   324  	// should not hit the fallback path
   325  	psNamed := &gadget.LaidOutStructure{
   326  		VolumeStructure: &gadget.VolumeStructure{
   327  			Name: "foo",
   328  		},
   329  		StartOffset: 123,
   330  	}
   331  	found, offs, err := gadget.FindDeviceForStructureWithFallback(psNamed)
   332  	c.Check(err, Equals, gadget.ErrDeviceNotFound)
   333  	c.Check(found, Equals, "")
   334  	c.Check(offs, Equals, gadget.Size(0))
   335  }
   336  
   337  func (d *deviceSuite) TestDeviceFindFallbackNotForFilesystem(c *C) {
   338  	d.setUpWritableFallback(c, writableMountInfo)
   339  
   340  	psFs := &gadget.LaidOutStructure{
   341  		VolumeStructure: &gadget.VolumeStructure{
   342  			Label:      "foo",
   343  			Filesystem: "ext4",
   344  		},
   345  		StartOffset: 123,
   346  	}
   347  	found, offs, err := gadget.FindDeviceForStructureWithFallback(psFs)
   348  	c.Check(err, ErrorMatches, "internal error: cannot use with filesystem structures")
   349  	c.Check(found, Equals, "")
   350  	c.Check(offs, Equals, gadget.Size(0))
   351  }
   352  
   353  func (d *deviceSuite) TestDeviceFindFallbackBadMountInfo(c *C) {
   354  	d.setUpWritableFallback(c, "garbage")
   355  	psFs := &gadget.LaidOutStructure{
   356  		VolumeStructure: &gadget.VolumeStructure{
   357  			Name: "foo",
   358  			Type: "bare",
   359  		},
   360  		StartOffset: 123,
   361  	}
   362  	found, offs, err := gadget.FindDeviceForStructureWithFallback(psFs)
   363  	c.Check(err, ErrorMatches, "cannot read mount info: .*")
   364  	c.Check(found, Equals, "")
   365  	c.Check(offs, Equals, gadget.Size(0))
   366  }
   367  
   368  func (d *deviceSuite) TestDeviceFindFallbackPassThrough(c *C) {
   369  	err := ioutil.WriteFile(filepath.Join(d.dir, "/dev/disk/by-partlabel/foo"), nil, 0644)
   370  	c.Assert(err, IsNil)
   371  
   372  	ps := &gadget.LaidOutStructure{
   373  		VolumeStructure: &gadget.VolumeStructure{
   374  			Name: "foo",
   375  		},
   376  	}
   377  	found, offs, err := gadget.FindDeviceForStructureWithFallback(ps)
   378  	c.Check(err, ErrorMatches, `candidate .*/dev/disk/by-partlabel/foo is not a symlink`)
   379  	c.Check(found, Equals, "")
   380  	c.Check(offs, Equals, gadget.Size(0))
   381  
   382  	// create a proper symlink
   383  	err = os.Remove(filepath.Join(d.dir, "/dev/disk/by-partlabel/foo"))
   384  	c.Assert(err, IsNil)
   385  	err = os.Symlink("../../fakedevice", filepath.Join(d.dir, "/dev/disk/by-partlabel/foo"))
   386  	c.Assert(err, IsNil)
   387  
   388  	// this should be happy again
   389  	found, offs, err = gadget.FindDeviceForStructureWithFallback(ps)
   390  	c.Assert(err, IsNil)
   391  	c.Check(found, Equals, filepath.Join(d.dir, "/dev/fakedevice"))
   392  	c.Check(offs, Equals, gadget.Size(0))
   393  }
   394  
   395  func (d *deviceSuite) TestDeviceEncodeLabel(c *C) {
   396  	// Test output obtained with the following program:
   397  	//
   398  	// #include <string.h>
   399  	// #include <stdio.h>
   400  	// #include <blkid/blkid.h>
   401  	// int main(int argc, char *argv[]) {
   402  	//   char out[2048] = {0};
   403  	//   if (blkid_encode_string(argv[1], out, sizeof(out)) != 0) {
   404  	//     fprintf(stderr, "failed to encode string\n");
   405  	//     return 1;
   406  	//   }
   407  	//   fprintf(stdout, out);
   408  	//   return 0;
   409  	// }
   410  	for i, tc := range []struct {
   411  		what string
   412  		exp  string
   413  	}{
   414  		{"foo", "foo"},
   415  		{"foo bar", `foo\x20bar`},
   416  		{"foo/bar", `foo\x2fbar`},
   417  		{"foo:#.@bar", `foo:#.@bar`},
   418  		{"foo..bar", `foo..bar`},
   419  		{"foo/../bar", `foo\x2f..\x2fbar`},
   420  		{"foo\\bar", `foo\x5cbar`},
   421  		{"Новый_том", "Новый_том"},
   422  		{"befs_test", "befs_test"},
   423  		{"P01_S16A", "P01_S16A"},
   424  		{"pinkié pie", `pinkié\x20pie`},
   425  		{"(EFI Boot)", `\x28EFI\x20Boot\x29`},
   426  		{"[System Boot]", `\x5bSystem\x20Boot\x5d`},
   427  	} {
   428  		c.Logf("tc: %v %q", i, tc)
   429  		res := gadget.EncodeLabel(tc.what)
   430  		c.Check(res, Equals, tc.exp)
   431  	}
   432  }
   433  
   434  func (d *deviceSuite) TestDeviceFindMountPointErrorsWithBare(c *C) {
   435  	p, err := gadget.FindMountPointForStructure(&gadget.LaidOutStructure{
   436  		VolumeStructure: &gadget.VolumeStructure{
   437  			// no filesystem
   438  			Filesystem: "",
   439  		},
   440  	})
   441  	c.Assert(err, ErrorMatches, "no filesystem defined")
   442  	c.Check(p, Equals, "")
   443  
   444  	p, err = gadget.FindMountPointForStructure(&gadget.LaidOutStructure{
   445  		VolumeStructure: &gadget.VolumeStructure{
   446  			// also counts as bare structure
   447  			Filesystem: "none",
   448  		},
   449  	})
   450  	c.Assert(err, ErrorMatches, "no filesystem defined")
   451  	c.Check(p, Equals, "")
   452  }
   453  
   454  func (d *deviceSuite) TestDeviceFindMountPointErrorsFromDevice(c *C) {
   455  	p, err := gadget.FindMountPointForStructure(&gadget.LaidOutStructure{
   456  		VolumeStructure: &gadget.VolumeStructure{
   457  			Label:      "bar",
   458  			Filesystem: "ext4",
   459  		},
   460  	})
   461  	c.Assert(err, ErrorMatches, "device not found")
   462  	c.Check(p, Equals, "")
   463  
   464  	p, err = gadget.FindMountPointForStructure(&gadget.LaidOutStructure{
   465  		VolumeStructure: &gadget.VolumeStructure{
   466  			Name:       "bar",
   467  			Filesystem: "ext4",
   468  		},
   469  	})
   470  	c.Assert(err, ErrorMatches, "device not found")
   471  	c.Check(p, Equals, "")
   472  }
   473  
   474  func mockProcSelfFilesystem(c *C, root, content string) {
   475  	psmi := filepath.Join(root, osutil.ProcSelfMountInfo)
   476  	err := os.MkdirAll(filepath.Dir(psmi), 0755)
   477  	c.Assert(err, IsNil)
   478  	err = ioutil.WriteFile(psmi, []byte(content), 0644)
   479  	c.Assert(err, IsNil)
   480  }
   481  
   482  func (d *deviceSuite) TestDeviceFindMountPointErrorBadMountinfo(c *C) {
   483  	// taken from core18 system
   484  
   485  	fakedevice := filepath.Join(d.dir, "/dev/sda2")
   486  	err := ioutil.WriteFile(fakedevice, []byte(""), 0644)
   487  	c.Assert(err, IsNil)
   488  	err = os.Symlink(fakedevice, filepath.Join(d.dir, "/dev/disk/by-label/system-boot"))
   489  	c.Assert(err, IsNil)
   490  
   491  	mockProcSelfFilesystem(c, d.dir, "garbage")
   492  
   493  	found, err := gadget.FindMountPointForStructure(&gadget.LaidOutStructure{
   494  		VolumeStructure: &gadget.VolumeStructure{
   495  			Name:       "EFI System",
   496  			Label:      "system-boot",
   497  			Filesystem: "vfat",
   498  		},
   499  	})
   500  	c.Check(err, ErrorMatches, "cannot read mount info: .*")
   501  	c.Check(found, Equals, "")
   502  }
   503  
   504  func (d *deviceSuite) TestDeviceFindMountPointByLabeHappySimple(c *C) {
   505  	// taken from core18 system
   506  
   507  	fakedevice := filepath.Join(d.dir, "/dev/sda2")
   508  	err := ioutil.WriteFile(fakedevice, []byte(""), 0644)
   509  	c.Assert(err, IsNil)
   510  	err = os.Symlink(fakedevice, filepath.Join(d.dir, "/dev/disk/by-label/system-boot"))
   511  	c.Assert(err, IsNil)
   512  	err = os.Symlink(fakedevice, filepath.Join(d.dir, `/dev/disk/by-partlabel/EFI\x20System`))
   513  	c.Assert(err, IsNil)
   514  
   515  	mountInfo := `
   516  170 27 8:2 / /boot/efi rw,relatime shared:58 - vfat ${rootDir}/dev/sda2 rw,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,errors=remount-ro
   517  172 27 8:2 /EFI/ubuntu /boot/grub rw,relatime shared:58 - vfat ${rootDir}/dev/sda2 rw,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,errors=remount-ro
   518  `
   519  	mockProcSelfFilesystem(c, d.dir, strings.Replace(mountInfo[1:], "${rootDir}", d.dir, -1))
   520  
   521  	found, err := gadget.FindMountPointForStructure(&gadget.LaidOutStructure{
   522  		VolumeStructure: &gadget.VolumeStructure{
   523  			Name:       "EFI System",
   524  			Label:      "system-boot",
   525  			Filesystem: "vfat",
   526  		},
   527  	})
   528  	c.Check(err, IsNil)
   529  	c.Check(found, Equals, "/boot/efi")
   530  }
   531  
   532  func (d *deviceSuite) TestDeviceFindMountPointByLabeHappyReversed(c *C) {
   533  	// taken from core18 system
   534  
   535  	fakedevice := filepath.Join(d.dir, "/dev/sda2")
   536  	err := ioutil.WriteFile(fakedevice, []byte(""), 0644)
   537  	c.Assert(err, IsNil)
   538  	// single property match
   539  	err = os.Symlink(fakedevice, filepath.Join(d.dir, "/dev/disk/by-label/system-boot"))
   540  	c.Assert(err, IsNil)
   541  
   542  	// reverse the order of lines
   543  	mountInfoReversed := `
   544  172 27 8:2 /EFI/ubuntu /boot/grub rw,relatime shared:58 - vfat ${rootDir}/dev/sda2 rw,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,errors=remount-ro
   545  170 27 8:2 / /boot/efi rw,relatime shared:58 - vfat ${rootDir}/dev/sda2 rw,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,errors=remount-ro
   546  `
   547  
   548  	mockProcSelfFilesystem(c, d.dir, strings.Replace(mountInfoReversed[1:], "${rootDir}", d.dir, -1))
   549  
   550  	found, err := gadget.FindMountPointForStructure(&gadget.LaidOutStructure{
   551  		VolumeStructure: &gadget.VolumeStructure{
   552  			Name:       "EFI System",
   553  			Label:      "system-boot",
   554  			Filesystem: "vfat",
   555  		},
   556  	})
   557  	c.Check(err, IsNil)
   558  	c.Check(found, Equals, "/boot/efi")
   559  }
   560  
   561  func (d *deviceSuite) TestDeviceFindMountPointPicksFirstMatch(c *C) {
   562  	// taken from core18 system
   563  
   564  	fakedevice := filepath.Join(d.dir, "/dev/sda2")
   565  	err := ioutil.WriteFile(fakedevice, []byte(""), 0644)
   566  	c.Assert(err, IsNil)
   567  	// single property match
   568  	err = os.Symlink(fakedevice, filepath.Join(d.dir, "/dev/disk/by-label/system-boot"))
   569  	c.Assert(err, IsNil)
   570  
   571  	mountInfo := `
   572  852 134 8:2 / /mnt/foo rw,relatime shared:58 - vfat ${rootDir}/dev/sda2 rw,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,errors=remount-ro
   573  172 27 8:2 /EFI/ubuntu /boot/grub rw,relatime shared:58 - vfat ${rootDir}/dev/sda2 rw,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,errors=remount-ro
   574  170 27 8:2 / /boot/efi rw,relatime shared:58 - vfat ${rootDir}/dev/sda2 rw,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,errors=remount-ro
   575  `
   576  
   577  	mockProcSelfFilesystem(c, d.dir, strings.Replace(mountInfo[1:], "${rootDir}", d.dir, -1))
   578  
   579  	found, err := gadget.FindMountPointForStructure(&gadget.LaidOutStructure{
   580  		VolumeStructure: &gadget.VolumeStructure{
   581  			Name:       "EFI System",
   582  			Label:      "system-boot",
   583  			Filesystem: "vfat",
   584  		},
   585  	})
   586  	c.Check(err, IsNil)
   587  	c.Check(found, Equals, "/mnt/foo")
   588  }
   589  
   590  func (d *deviceSuite) TestDeviceFindMountPointByPartlabel(c *C) {
   591  	fakedevice := filepath.Join(d.dir, "/dev/fakedevice")
   592  	err := ioutil.WriteFile(fakedevice, []byte(""), 0644)
   593  	c.Assert(err, IsNil)
   594  	err = os.Symlink(fakedevice, filepath.Join(d.dir, `/dev/disk/by-partlabel/pinkié\x20pie`))
   595  	c.Assert(err, IsNil)
   596  
   597  	mountInfo := `
   598  170 27 8:2 / /mount-point rw,relatime shared:58 - ext4 ${rootDir}/dev/fakedevice rw
   599  `
   600  
   601  	mockProcSelfFilesystem(c, d.dir, strings.Replace(mountInfo[1:], "${rootDir}", d.dir, -1))
   602  
   603  	found, err := gadget.FindMountPointForStructure(&gadget.LaidOutStructure{
   604  		VolumeStructure: &gadget.VolumeStructure{
   605  			Name:       "pinkié pie",
   606  			Filesystem: "ext4",
   607  		},
   608  	})
   609  	c.Check(err, IsNil)
   610  	c.Check(found, Equals, "/mount-point")
   611  }
   612  
   613  func (d *deviceSuite) TestDeviceFindMountPointChecksFilesystem(c *C) {
   614  	fakedevice := filepath.Join(d.dir, "/dev/fakedevice")
   615  	err := ioutil.WriteFile(fakedevice, []byte(""), 0644)
   616  	c.Assert(err, IsNil)
   617  	err = os.Symlink(fakedevice, filepath.Join(d.dir, `/dev/disk/by-partlabel/label`))
   618  	c.Assert(err, IsNil)
   619  
   620  	mountInfo := `
   621  170 27 8:2 / /mount-point rw,relatime shared:58 - vfat ${rootDir}/dev/fakedevice rw
   622  `
   623  
   624  	mockProcSelfFilesystem(c, d.dir, strings.Replace(mountInfo[1:], "${rootDir}", d.dir, -1))
   625  
   626  	found, err := gadget.FindMountPointForStructure(&gadget.LaidOutStructure{
   627  		VolumeStructure: &gadget.VolumeStructure{
   628  			Name: "label",
   629  			// different fs than mount entry
   630  			Filesystem: "ext4",
   631  		},
   632  	})
   633  	c.Check(err, ErrorMatches, "mount point not found")
   634  	c.Check(found, Equals, "")
   635  }