Fix panic in parsing /etc/os-release

Signed-off-by: Vincent Demeester <vincent@sbr.pm>
This commit is contained in:
Vincent Demeester 2015-10-29 09:16:21 +01:00
parent b09a452c1f
commit 7b102dc114
2 changed files with 131 additions and 36 deletions

View File

@ -3,9 +3,14 @@
package operatingsystem
import (
"bufio"
"bytes"
"errors"
"fmt"
"io/ioutil"
"os"
"strings"
"github.com/mattn/go-shellwords"
)
var (
@ -18,15 +23,34 @@ var (
// GetOperatingSystem gets the name of the current operating system.
func GetOperatingSystem() (string, error) {
b, err := ioutil.ReadFile(etcOsRelease)
osReleaseFile, err := os.Open(etcOsRelease)
if err != nil {
return "", err
}
if i := bytes.Index(b, []byte("PRETTY_NAME")); i >= 0 {
b = b[i+13:]
return string(b[:bytes.IndexByte(b, '"')]), nil
defer osReleaseFile.Close()
var prettyName string
scanner := bufio.NewScanner(osReleaseFile)
for scanner.Scan() {
line := scanner.Text()
if strings.HasPrefix(line, "PRETTY_NAME=") {
data := strings.SplitN(line, "=", 2)
prettyNames, err := shellwords.Parse(data[1])
if err != nil {
return "", fmt.Errorf("PRETTY_NAME is invalid: %s", err.Error())
}
if len(prettyNames) != 1 {
return "", fmt.Errorf("PRETTY_NAME needs to be enclosed by quotes if they have spaces: %s", data[1])
}
prettyName = prettyNames[0]
}
}
return "", errors.New("PRETTY_NAME not found")
if prettyName != "" {
return prettyName, nil
}
// If not set, defaults to PRETTY_NAME="Linux"
// c.f. http://www.freedesktop.org/software/systemd/man/os-release.html
return "Linux", nil
}
// IsContainerized returns true if we are running inside a container.

View File

@ -10,9 +10,74 @@ import (
)
func TestGetOperatingSystem(t *testing.T) {
var (
backup = etcOsRelease
ubuntuTrusty = []byte(`NAME="Ubuntu"
var backup = etcOsRelease
invalids := []struct {
content string
errorExpected string
}{
{
`PRETTY_NAME=Source Mage GNU/Linux
PRETTY_NAME=Ubuntu 14.04.LTS`,
"PRETTY_NAME needs to be enclosed by quotes if they have spaces: Source Mage GNU/Linux",
},
{
`PRETTY_NAME="Ubuntu Linux
PRETTY_NAME=Ubuntu 14.04.LTS`,
"PRETTY_NAME is invalid: invalid command line string",
},
{
`PRETTY_NAME=Ubuntu'
PRETTY_NAME=Ubuntu 14.04.LTS`,
"PRETTY_NAME is invalid: invalid command line string",
},
{
`PRETTY_NAME'
PRETTY_NAME=Ubuntu 14.04.LTS`,
"PRETTY_NAME needs to be enclosed by quotes if they have spaces: Ubuntu 14.04.LTS",
},
}
valids := []struct {
content string
expected string
}{
{
`NAME="Ubuntu"
PRETTY_NAME_AGAIN="Ubuntu 14.04.LTS"
VERSION="14.04, Trusty Tahr"
ID=ubuntu
ID_LIKE=debian
VERSION_ID="14.04"
HOME_URL="http://www.ubuntu.com/"
SUPPORT_URL="http://help.ubuntu.com/"
BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"`,
"Linux",
},
{
`NAME="Ubuntu"
VERSION="14.04, Trusty Tahr"
ID=ubuntu
ID_LIKE=debian
VERSION_ID="14.04"
HOME_URL="http://www.ubuntu.com/"
SUPPORT_URL="http://help.ubuntu.com/"
BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"`,
"Linux",
},
{
`NAME=Gentoo
ID=gentoo
PRETTY_NAME="Gentoo/Linux"
ANSI_COLOR="1;32"
HOME_URL="http://www.gentoo.org/"
SUPPORT_URL="http://www.gentoo.org/main/en/support.xml"
BUG_REPORT_URL="https://bugs.gentoo.org/"
`,
"Gentoo/Linux",
},
{
`NAME="Ubuntu"
VERSION="14.04, Trusty Tahr"
ID=ubuntu
ID_LIKE=debian
@ -20,24 +85,28 @@ PRETTY_NAME="Ubuntu 14.04 LTS"
VERSION_ID="14.04"
HOME_URL="http://www.ubuntu.com/"
SUPPORT_URL="http://help.ubuntu.com/"
BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"`)
gentoo = []byte(`NAME=Gentoo
ID=gentoo
PRETTY_NAME="Gentoo/Linux"
ANSI_COLOR="1;32"
HOME_URL="http://www.gentoo.org/"
SUPPORT_URL="http://www.gentoo.org/main/en/support.xml"
BUG_REPORT_URL="https://bugs.gentoo.org/"
`)
noPrettyName = []byte(`NAME="Ubuntu"
BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"`,
"Ubuntu 14.04 LTS",
},
{
`NAME="Ubuntu"
VERSION="14.04, Trusty Tahr"
ID=ubuntu
ID_LIKE=debian
VERSION_ID="14.04"
HOME_URL="http://www.ubuntu.com/"
SUPPORT_URL="http://help.ubuntu.com/"
BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"`)
)
PRETTY_NAME='Ubuntu 14.04 LTS'`,
"Ubuntu 14.04 LTS",
},
{
`PRETTY_NAME=Source
NAME="Source Mage"`,
"Source",
},
{
`PRETTY_NAME=Source
PRETTY_NAME="Source Mage"`,
"Source Mage",
},
}
dir := os.TempDir()
etcOsRelease = filepath.Join(dir, "etcOsRelease")
@ -47,21 +116,23 @@ BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"`)
etcOsRelease = backup
}()
for expect, osRelease := range map[string][]byte{
"Ubuntu 14.04 LTS": ubuntuTrusty,
"Gentoo/Linux": gentoo,
"": noPrettyName,
} {
if err := ioutil.WriteFile(etcOsRelease, osRelease, 0600); err != nil {
for _, elt := range invalids {
if err := ioutil.WriteFile(etcOsRelease, []byte(elt.content), 0600); err != nil {
t.Fatalf("failed to write to %s: %v", etcOsRelease, err)
}
s, err := GetOperatingSystem()
if s != expect {
if expect == "" {
t.Fatalf("Expected error 'PRETTY_NAME not found', but got %v", err)
} else {
t.Fatalf("Expected '%s', but got '%s'. Err=%v", expect, s, err)
}
if err == nil || err.Error() != elt.errorExpected {
t.Fatalf("Expected an error %q, got %q (err: %v)", elt.errorExpected, s, err)
}
}
for _, elt := range valids {
if err := ioutil.WriteFile(etcOsRelease, []byte(elt.content), 0600); err != nil {
t.Fatalf("failed to write to %s: %v", etcOsRelease, err)
}
s, err := GetOperatingSystem()
if err != nil || s != elt.expected {
t.Fatalf("Expected %q, got %q (err: %v)", elt.expected, s, err)
}
}
}