diff --git a/cmd/snap-preseed/preseed_linux.go b/cmd/snap-preseed/preseed_linux.go index 6c6e8194456..5dcff029a7c 100644 --- a/cmd/snap-preseed/preseed_linux.go +++ b/cmd/snap-preseed/preseed_linux.go @@ -159,7 +159,7 @@ type targetSnapdInfo struct { func chooseTargetSnapdVersion() (*targetSnapdInfo, error) { // read snapd version from the mounted core/snapd snap infoPath := filepath.Join(snapdMountPath, dirs.CoreLibExecDir, "info") - verFromSnap, err := snapdtool.SnapdVersionFromInfoFile(infoPath) + verFromSnap, _, err := snapdtool.SnapdVersionFromInfoFile(infoPath) if err != nil { return nil, err } @@ -167,7 +167,7 @@ func chooseTargetSnapdVersion() (*targetSnapdInfo, error) { // read snapd version from the main fs under chroot (snapd from the deb); // assumes running under chroot already. infoPath = filepath.Join(dirs.GlobalRootDir, dirs.CoreLibExecDir, "info") - verFromDeb, err := snapdtool.SnapdVersionFromInfoFile(infoPath) + verFromDeb, _, err := snapdtool.SnapdVersionFromInfoFile(infoPath) if err != nil { return nil, err } diff --git a/mkversion.sh b/mkversion.sh index 2fe1edf51ad..7d6d108d218 100755 --- a/mkversion.sh +++ b/mkversion.sh @@ -130,4 +130,5 @@ EOF cat < "$PKG_BUILDDIR/data/info" VERSION=$v +SNAPD_APPARMOR_REEXEC=0 EOF diff --git a/snapdtool/info_file.go b/snapdtool/info_file.go index 2780334501e..228b28ff963 100644 --- a/snapdtool/info_file.go +++ b/snapdtool/info_file.go @@ -20,34 +20,53 @@ package snapdtool import ( - "bytes" + "bufio" "fmt" - "io/ioutil" + "os" + "strings" ) // SnapdVersionFromInfoFile returns snapd version read for the // given info" file, pointed by infoPath. -// The format of the "info" file is a single line with "VERSION=..." -// in it. The file is produced by mkversion.sh and normally installed -// along snapd binary in /usr/lib/snapd. -func SnapdVersionFromInfoFile(infoPath string) (string, error) { - content, err := ioutil.ReadFile(infoPath) +// The format of the "info" file are lines with "KEY=VALUE" with the typical key +// being just VERSION. The file is produced by mkversion.sh and normally +// installed along snapd binary in /usr/lib/snapd. +// Other typical keys in this file include SNAPD_APPARMOR_REEXEC, which +// indicates whether or not the snapd-apparmor binary installed via the +// traditional linux package of snapd supports re-exec into the version in the +// snapd or core snaps. +func SnapdVersionFromInfoFile(infoPath string) (version string, flags map[string]string, err error) { + f, err := os.Open(infoPath) if err != nil { - return "", fmt.Errorf("cannot open snapd info file %q: %s", infoPath, err) + return "", nil, fmt.Errorf("cannot open snapd info file %q: %s", infoPath, err) } + defer f.Close() - if !bytes.HasPrefix(content, []byte("VERSION=")) { - idx := bytes.Index(content, []byte("\nVERSION=")) - if idx < 0 { - return "", fmt.Errorf("cannot find snapd version information in %q", content) + flags = map[string]string{} + + scanner := bufio.NewScanner(f) + for scanner.Scan() { + line := scanner.Text() + if strings.HasPrefix(line, "VERSION=") { + version = strings.TrimPrefix(line, "VERSION=") + } else { + keyVal := strings.SplitN(line, "=", 2) + if len(keyVal) != 2 { + // potentially malformed line, just skip it + continue + } + + flags[keyVal[0]] = keyVal[1] } - content = content[idx+1:] } - content = content[8:] - idx := bytes.IndexByte(content, '\n') - if idx > -1 { - content = content[:idx] + + if err := scanner.Err(); err != nil { + return "", nil, fmt.Errorf("error reading snapd info file %q: %v", infoPath, err) + } + + if version == "" { + return "", nil, fmt.Errorf("cannot find snapd version information in file %q", infoPath) } - return string(content), nil + return version, flags, nil } diff --git a/snapdtool/info_file_test.go b/snapdtool/info_file_test.go index 1ce9a5dd236..ab41f567b8d 100644 --- a/snapdtool/info_file_test.go +++ b/snapdtool/info_file_test.go @@ -20,6 +20,7 @@ package snapdtool_test import ( + "fmt" "io/ioutil" "path/filepath" @@ -33,7 +34,7 @@ type infoFileSuite struct{} var _ = Suite(&infoFileSuite{}) func (s *infoFileSuite) TestNoVersionFile(c *C) { - _, err := snapdtool.SnapdVersionFromInfoFile("/non-existing-file") + _, _, err := snapdtool.SnapdVersionFromInfoFile("/non-existing-file") c.Assert(err, ErrorMatches, `cannot open snapd info file "/non-existing-file":.*`) } @@ -42,8 +43,8 @@ func (s *infoFileSuite) TestNoVersionData(c *C) { infoFile := filepath.Join(top, "info") c.Assert(ioutil.WriteFile(infoFile, []byte("foo"), 0644), IsNil) - _, err := snapdtool.SnapdVersionFromInfoFile(infoFile) - c.Assert(err, ErrorMatches, `cannot find snapd version information in "foo"`) + _, _, err := snapdtool.SnapdVersionFromInfoFile(infoFile) + c.Assert(err, ErrorMatches, fmt.Sprintf(`cannot find snapd version information in file %q`, infoFile)) } func (s *infoFileSuite) TestVersionHappy(c *C) { @@ -51,7 +52,19 @@ func (s *infoFileSuite) TestVersionHappy(c *C) { infoFile := filepath.Join(top, "info") c.Assert(ioutil.WriteFile(infoFile, []byte("VERSION=1.2.3"), 0644), IsNil) - ver, err := snapdtool.SnapdVersionFromInfoFile(infoFile) + ver, flags, err := snapdtool.SnapdVersionFromInfoFile(infoFile) c.Assert(err, IsNil) c.Check(ver, Equals, "1.2.3") + c.Assert(flags, HasLen, 0) +} + +func (s *infoFileSuite) TestInfoVersionFlags(c *C) { + top := c.MkDir() + infoFile := filepath.Join(top, "info") + c.Assert(ioutil.WriteFile(infoFile, []byte("VERSION=1.2.3\nFOO=BAR"), 0644), IsNil) + + ver, flags, err := snapdtool.SnapdVersionFromInfoFile(infoFile) + c.Assert(err, IsNil) + c.Check(ver, Equals, "1.2.3") + c.Assert(flags, DeepEquals, map[string]string{"FOO": "BAR"}) } diff --git a/snapdtool/tool_linux.go b/snapdtool/tool_linux.go index 986b106bddb..8e25278fede 100644 --- a/snapdtool/tool_linux.go +++ b/snapdtool/tool_linux.go @@ -77,7 +77,7 @@ func distroSupportsReExec() bool { // version of core that do not yet have it. func coreSupportsReExec(coreOrSnapdPath string) bool { infoPath := filepath.Join(coreOrSnapdPath, filepath.Join(dirs.CoreLibExecDir, "info")) - ver, err := SnapdVersionFromInfoFile(infoPath) + ver, _, err := SnapdVersionFromInfoFile(infoPath) if err != nil { logger.Noticef("%v", err) return false