github.com/stolowski/snapd@v0.0.0-20210407085831-115137ce5a22/boot/cmdline_test.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2020 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 boot_test 21 22 import ( 23 "io/ioutil" 24 "os" 25 "path/filepath" 26 27 . "gopkg.in/check.v1" 28 29 "github.com/snapcore/snapd/boot" 30 "github.com/snapcore/snapd/boot/boottest" 31 "github.com/snapcore/snapd/bootloader" 32 "github.com/snapcore/snapd/bootloader/bootloadertest" 33 "github.com/snapcore/snapd/osutil" 34 "github.com/snapcore/snapd/testutil" 35 ) 36 37 var _ = Suite(&kernelCommandLineSuite{}) 38 39 // baseBootSuite is used to setup the common test environment 40 type kernelCommandLineSuite struct { 41 testutil.BaseTest 42 rootDir string 43 } 44 45 func (s *kernelCommandLineSuite) SetUpTest(c *C) { 46 s.BaseTest.SetUpTest(c) 47 s.rootDir = c.MkDir() 48 49 err := os.MkdirAll(filepath.Join(s.rootDir, "proc"), 0755) 50 c.Assert(err, IsNil) 51 restore := osutil.MockProcCmdline(filepath.Join(s.rootDir, "proc/cmdline")) 52 s.AddCleanup(restore) 53 } 54 55 func (s *kernelCommandLineSuite) mockProcCmdlineContent(c *C, newContent string) { 56 mockProcCmdline := filepath.Join(s.rootDir, "proc/cmdline") 57 err := ioutil.WriteFile(mockProcCmdline, []byte(newContent), 0644) 58 c.Assert(err, IsNil) 59 } 60 61 func (s *kernelCommandLineSuite) TestModeAndLabel(c *C) { 62 for _, tc := range []struct { 63 cmd string 64 mode string 65 label string 66 err string 67 }{{ 68 cmd: "snapd_recovery_mode= snapd_recovery_system=this-is-a-label other-option=foo", 69 mode: boot.ModeInstall, 70 label: "this-is-a-label", 71 }, { 72 cmd: "snapd_recovery_system=label foo=bar foobaz=\\0\\0123 snapd_recovery_mode=install", 73 label: "label", 74 mode: boot.ModeInstall, 75 }, { 76 cmd: "snapd_recovery_mode=run snapd_recovery_system=1234", 77 mode: boot.ModeRun, 78 }, { 79 cmd: "option=1 other-option=\0123 none", 80 err: "cannot detect mode nor recovery system to use", 81 }, { 82 cmd: "snapd_recovery_mode=install-foo", 83 err: `cannot use unknown mode "install-foo"`, 84 }, { 85 // no recovery system label 86 cmd: "snapd_recovery_mode=install foo=bar", 87 err: `cannot specify install mode without system label`, 88 }, { 89 cmd: "snapd_recovery_system=1234", 90 err: `cannot specify system label without a mode`, 91 }, { 92 // multiple kernel command line params end up using the last one - this 93 // effectively matches the kernel handling too 94 cmd: "snapd_recovery_mode=install snapd_recovery_system=1234 snapd_recovery_mode=run", 95 mode: "run", 96 // label gets unset because it's not used for run mode 97 label: "", 98 }, { 99 cmd: "snapd_recovery_system=not-this-one snapd_recovery_mode=install snapd_recovery_system=1234", 100 mode: "install", 101 label: "1234", 102 }} { 103 c.Logf("tc: %q", tc) 104 s.mockProcCmdlineContent(c, tc.cmd) 105 106 mode, label, err := boot.ModeAndRecoverySystemFromKernelCommandLine() 107 if tc.err == "" { 108 c.Assert(err, IsNil) 109 c.Check(mode, Equals, tc.mode) 110 c.Check(label, Equals, tc.label) 111 } else { 112 c.Assert(err, ErrorMatches, tc.err) 113 } 114 } 115 } 116 117 func (s *kernelCommandLineSuite) TestComposeCommandLineNotManagedHappy(c *C) { 118 model := boottest.MakeMockUC20Model() 119 120 bl := bootloadertest.Mock("btloader", c.MkDir()) 121 bootloader.Force(bl) 122 defer bootloader.Force(nil) 123 124 cmdline, err := boot.ComposeRecoveryCommandLine(model, "20200314") 125 c.Assert(err, IsNil) 126 c.Assert(cmdline, Equals, "") 127 128 cmdline, err = boot.ComposeCommandLine(model) 129 c.Assert(err, IsNil) 130 c.Assert(cmdline, Equals, "") 131 132 tbl := bl.WithTrustedAssets() 133 bootloader.Force(tbl) 134 135 cmdline, err = boot.ComposeRecoveryCommandLine(model, "20200314") 136 c.Assert(err, IsNil) 137 c.Assert(cmdline, Equals, "snapd_recovery_mode=recover snapd_recovery_system=20200314") 138 139 cmdline, err = boot.ComposeCommandLine(model) 140 c.Assert(err, IsNil) 141 c.Assert(cmdline, Equals, "snapd_recovery_mode=run") 142 } 143 144 func (s *kernelCommandLineSuite) TestComposeCommandLineNotUC20(c *C) { 145 model := boottest.MakeMockModel() 146 147 bl := bootloadertest.Mock("btloader", c.MkDir()) 148 bootloader.Force(bl) 149 defer bootloader.Force(nil) 150 cmdline, err := boot.ComposeRecoveryCommandLine(model, "20200314") 151 c.Assert(err, IsNil) 152 c.Check(cmdline, Equals, "") 153 154 cmdline, err = boot.ComposeCommandLine(model) 155 c.Assert(err, IsNil) 156 c.Check(cmdline, Equals, "") 157 } 158 159 func (s *kernelCommandLineSuite) TestComposeCommandLineManagedHappy(c *C) { 160 model := boottest.MakeMockUC20Model() 161 162 tbl := bootloadertest.Mock("btloader", c.MkDir()).WithTrustedAssets() 163 bootloader.Force(tbl) 164 defer bootloader.Force(nil) 165 166 tbl.StaticCommandLine = "panic=-1" 167 168 cmdline, err := boot.ComposeRecoveryCommandLine(model, "20200314") 169 c.Assert(err, IsNil) 170 c.Assert(cmdline, Equals, "snapd_recovery_mode=recover snapd_recovery_system=20200314 panic=-1") 171 cmdline, err = boot.ComposeCommandLine(model) 172 c.Assert(err, IsNil) 173 c.Assert(cmdline, Equals, "snapd_recovery_mode=run panic=-1") 174 175 cmdline, err = boot.ComposeRecoveryCommandLine(model, "20200314") 176 c.Assert(err, IsNil) 177 c.Assert(cmdline, Equals, "snapd_recovery_mode=recover snapd_recovery_system=20200314 panic=-1") 178 cmdline, err = boot.ComposeCommandLine(model) 179 c.Assert(err, IsNil) 180 c.Assert(cmdline, Equals, "snapd_recovery_mode=run panic=-1") 181 } 182 183 func (s *kernelCommandLineSuite) TestComposeCandidateCommandLineManagedHappy(c *C) { 184 model := boottest.MakeMockUC20Model() 185 186 tbl := bootloadertest.Mock("btloader", c.MkDir()).WithTrustedAssets() 187 bootloader.Force(tbl) 188 defer bootloader.Force(nil) 189 190 tbl.StaticCommandLine = "panic=-1" 191 tbl.CandidateStaticCommandLine = "candidate panic=0" 192 193 cmdline, err := boot.ComposeCandidateCommandLine(model) 194 c.Assert(err, IsNil) 195 c.Assert(cmdline, Equals, "snapd_recovery_mode=run candidate panic=0") 196 } 197 198 func (s *kernelCommandLineSuite) TestComposeCandidateRecoveryCommandLineManagedHappy(c *C) { 199 model := boottest.MakeMockUC20Model() 200 201 tbl := bootloadertest.Mock("btloader", c.MkDir()).WithTrustedAssets() 202 bootloader.Force(tbl) 203 defer bootloader.Force(nil) 204 205 tbl.StaticCommandLine = "panic=-1" 206 tbl.CandidateStaticCommandLine = "candidate panic=0" 207 208 cmdline, err := boot.ComposeCandidateRecoveryCommandLine(model, "1234") 209 c.Assert(err, IsNil) 210 c.Check(cmdline, Equals, "snapd_recovery_mode=recover snapd_recovery_system=1234 candidate panic=0") 211 212 cmdline, err = boot.ComposeCandidateRecoveryCommandLine(model, "") 213 c.Assert(err, ErrorMatches, "internal error: system is unset") 214 c.Check(cmdline, Equals, "") 215 }