github.com/stolowski/snapd@v0.0.0-20210407085831-115137ce5a22/osutil/kcmdline_test.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2014-2015 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 osutil_test
    21  
    22  import (
    23  	"io/ioutil"
    24  	"path/filepath"
    25  
    26  	. "gopkg.in/check.v1"
    27  
    28  	"github.com/snapcore/snapd/osutil"
    29  )
    30  
    31  type kcmdlineTestSuite struct{}
    32  
    33  var _ = Suite(&kcmdlineTestSuite{})
    34  
    35  func (s *kcmdlineTestSuite) TestSplitKernelCommandLine(c *C) {
    36  	for idx, tc := range []struct {
    37  		cmd    string
    38  		exp    []string
    39  		errStr string
    40  	}{
    41  		{cmd: ``, exp: nil},
    42  		{cmd: `foo bar baz`, exp: []string{"foo", "bar", "baz"}},
    43  		{cmd: `foo=" many   spaces  " bar`, exp: []string{`foo=" many   spaces  "`, "bar"}},
    44  		{cmd: `foo="1$2"`, exp: []string{`foo="1$2"`}},
    45  		{cmd: `foo=1$2`, exp: []string{`foo=1$2`}},
    46  		{cmd: `foo= bar`, exp: []string{"foo=", "bar"}},
    47  		{cmd: `foo=""`, exp: []string{`foo=""`}},
    48  		{cmd: `   cpu=1,2,3   mem=0x2000;0x4000:$2  `, exp: []string{"cpu=1,2,3", "mem=0x2000;0x4000:$2"}},
    49  		{cmd: "isolcpus=1,2,10-20,100-2000:2/25", exp: []string{"isolcpus=1,2,10-20,100-2000:2/25"}},
    50  		// something more realistic
    51  		{
    52  			cmd: `BOOT_IMAGE=/vmlinuz-linux root=/dev/mapper/linux-root rw quiet loglevel=3 rd.udev.log_priority=3 vt.global_cursor_default=0 rd.luks.uuid=1a273f76-3118-434b-8597-a3b12a59e017 rd.luks.uuid=775e4582-33c1-423b-ac19-f734e0d5e21c rd.luks.options=discard,timeout=0 root=/dev/mapper/linux-root apparmor=1 security=apparmor`,
    53  			exp: []string{
    54  				"BOOT_IMAGE=/vmlinuz-linux",
    55  				"root=/dev/mapper/linux-root",
    56  				"rw", "quiet",
    57  				"loglevel=3",
    58  				"rd.udev.log_priority=3",
    59  				"vt.global_cursor_default=0",
    60  				"rd.luks.uuid=1a273f76-3118-434b-8597-a3b12a59e017",
    61  				"rd.luks.uuid=775e4582-33c1-423b-ac19-f734e0d5e21c",
    62  				"rd.luks.options=discard,timeout=0",
    63  				"root=/dev/mapper/linux-root",
    64  				"apparmor=1",
    65  				"security=apparmor",
    66  			},
    67  		},
    68  		// this is actually ok, eg. rd.luks.options=discard,timeout=0
    69  		{cmd: `a=b=`, exp: []string{"a=b="}},
    70  		// bad quoting, or otherwise malformed command line
    71  		{cmd: `foo="1$2`, errStr: "unbalanced quoting"},
    72  		{cmd: `"foo"`, errStr: "unexpected quoting"},
    73  		{cmd: `foo"foo"`, errStr: "unexpected quoting"},
    74  		{cmd: `foo=foo"`, errStr: "unexpected quoting"},
    75  		{cmd: `foo="a""b"`, errStr: "unexpected quoting"},
    76  		{cmd: `foo="a foo="b`, errStr: "unexpected argument"},
    77  		{cmd: `foo="a"="b"`, errStr: "unexpected assignment"},
    78  		{cmd: `=`, errStr: "unexpected assignment"},
    79  		{cmd: `a =`, errStr: "unexpected assignment"},
    80  		{cmd: `="foo"`, errStr: "unexpected assignment"},
    81  		{cmd: `a==`, errStr: "unexpected assignment"},
    82  		{cmd: `foo ==a`, errStr: "unexpected assignment"},
    83  	} {
    84  		c.Logf("%v: cmd: %q", idx, tc.cmd)
    85  		out, err := osutil.KernelCommandLineSplit(tc.cmd)
    86  		if tc.errStr != "" {
    87  			c.Assert(err, ErrorMatches, tc.errStr)
    88  			c.Check(out, IsNil)
    89  		} else {
    90  			c.Assert(err, IsNil)
    91  			c.Check(out, DeepEquals, tc.exp)
    92  		}
    93  	}
    94  }
    95  
    96  func (s *kcmdlineTestSuite) TestGetKernelCommandLineKeyValue(c *C) {
    97  	for _, t := range []struct {
    98  		cmdline string
    99  		keys    []string
   100  		exp     map[string]string
   101  		err     string
   102  		comment string
   103  	}{
   104  		{
   105  			cmdline: "",
   106  			comment: "empty cmdline",
   107  			keys:    []string{"foo"},
   108  		},
   109  		{
   110  			cmdline: "foo",
   111  			comment: "cmdline non-key-value",
   112  			keys:    []string{"foo"},
   113  		},
   114  		{
   115  			cmdline: "foo=1",
   116  			comment: "key-value pair",
   117  			keys:    []string{"foo"},
   118  			exp: map[string]string{
   119  				"foo": "1",
   120  			},
   121  		},
   122  		{
   123  			cmdline: "foo=1 otherfoo=2",
   124  			comment: "multiple key-value pairs",
   125  			keys:    []string{"foo", "otherfoo"},
   126  			exp: map[string]string{
   127  				"foo":      "1",
   128  				"otherfoo": "2",
   129  			},
   130  		},
   131  		{
   132  			cmdline: "foo=",
   133  			comment: "empty value in key-value pair",
   134  			keys:    []string{"foo"},
   135  			exp: map[string]string{
   136  				"foo": "",
   137  			},
   138  		},
   139  		{
   140  			cmdline: "foo=1 foo=2",
   141  			comment: "duplicated key-value pair uses last one",
   142  			keys:    []string{"foo"},
   143  			exp: map[string]string{
   144  				"foo": "2",
   145  			},
   146  		},
   147  		{
   148  			cmdline: "foo=1 foo foo2=other",
   149  			comment: "cmdline key-value pair and non-key-value",
   150  			keys:    []string{"foo"},
   151  			exp: map[string]string{
   152  				"foo": "1",
   153  			},
   154  		},
   155  		{
   156  			cmdline: "foo=a=1",
   157  			comment: "key-value pair with = in value",
   158  			keys:    []string{"foo"},
   159  			exp: map[string]string{
   160  				"foo": "a=1",
   161  			},
   162  		},
   163  		{
   164  			cmdline: "=foo",
   165  			comment: "missing key",
   166  			keys:    []string{"foo"},
   167  			err:     "unexpected assignment",
   168  		},
   169  		{
   170  			cmdline: `"foo`,
   171  			comment: "invalid kernel cmdline",
   172  			keys:    []string{"foo"},
   173  			err:     "unexpected quoting",
   174  		},
   175  	} {
   176  		cmdlineFile := filepath.Join(c.MkDir(), "cmdline")
   177  		err := ioutil.WriteFile(cmdlineFile, []byte(t.cmdline), 0644)
   178  		c.Assert(err, IsNil)
   179  		r := osutil.MockProcCmdline(cmdlineFile)
   180  		defer r()
   181  		res, err := osutil.KernelCommandLineKeyValues(t.keys...)
   182  		if t.err != "" {
   183  			c.Assert(err, ErrorMatches, t.err, Commentf(t.comment))
   184  		} else {
   185  			c.Assert(err, IsNil)
   186  			exp := t.exp
   187  			if t.exp == nil {
   188  				exp = map[string]string{}
   189  			}
   190  			c.Assert(res, DeepEquals, exp, Commentf(t.comment))
   191  		}
   192  	}
   193  }
   194  
   195  func (s *kcmdlineTestSuite) TestKernelCommandLine(c *C) {
   196  	d := c.MkDir()
   197  	newProcCmdline := filepath.Join(d, "cmdline")
   198  	restore := osutil.MockProcCmdline(newProcCmdline)
   199  	defer restore()
   200  
   201  	cmd, err := osutil.KernelCommandLine()
   202  	c.Assert(err, ErrorMatches, `.*/cmdline: no such file or directory`)
   203  	c.Check(cmd, Equals, "")
   204  
   205  	err = ioutil.WriteFile(newProcCmdline, []byte("foo bar baz panic=-1\n"), 0644)
   206  	c.Assert(err, IsNil)
   207  	cmd, err = osutil.KernelCommandLine()
   208  	c.Assert(err, IsNil)
   209  	c.Check(cmd, Equals, "foo bar baz panic=-1")
   210  }