-
Notifications
You must be signed in to change notification settings - Fork 2
/
version.go
131 lines (115 loc) · 3.62 KB
/
version.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Copyright 2016-2017 Kinvolk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package kernel
import (
"fmt"
"os"
"regexp"
"strconv"
)
var versionRegex = regexp.MustCompile(`^(\d+)\.(\d+).(\d+).*$`)
type Version struct {
Major int
Minor int
Patch int
VersionCode int
}
// KernelVersionFromReleaseString converts a release string with format
// 4.4.2[-1] to a kernel version number in LINUX_VERSION_CODE format.
// That is, for kernel "a.b.c", the version number will be (a<<16 + b<<8 + c)
func KernelVersionFromReleaseString(releaseString string) (Version, error) {
versionParts := versionRegex.FindStringSubmatch(releaseString)
if len(versionParts) != 4 {
return Version{}, fmt.Errorf("got invalid release version %q (expected format '4.3.2-1')", releaseString) //nolint:goerr113
}
major, err := strconv.Atoi(versionParts[1])
if err != nil {
return Version{}, err
}
minor, err := strconv.Atoi(versionParts[2])
if err != nil {
return Version{}, err
}
patch, err := strconv.Atoi(versionParts[3])
if err != nil {
return Version{}, err
}
out := major*256*256 + minor*256 + patch
return Version{
Major: major,
Minor: minor,
Patch: patch,
VersionCode: out,
}, nil
}
func currentVersionUbuntu() (Version, error) {
procVersion, err := os.ReadFile("/proc/version_signature")
if err != nil {
return Version{}, err
}
var u1, u2, releaseString string
_, err = fmt.Sscanf(string(procVersion), "%s %s %s", &u1, &u2, &releaseString)
if err != nil {
return Version{}, err
}
return KernelVersionFromReleaseString(releaseString)
}
var debianVersionRegex = regexp.MustCompile(`.* SMP Debian (\d+\.\d+.\d+-\d+)(?:\+[[:alnum:]]*)?.*`)
func parseDebianVersion(str string) (Version, error) {
match := debianVersionRegex.FindStringSubmatch(str)
if len(match) != 2 {
return Version{}, fmt.Errorf("failed to parse kernel version from /proc/version: %s", str) //nolint:goerr113
}
return KernelVersionFromReleaseString(match[1])
}
func currentVersionDebian() (Version, error) {
procVersion, err := os.ReadFile("/proc/version")
if err != nil {
return Version{}, fmt.Errorf("error reading /proc/version: %w", err)
}
return parseDebianVersion(string(procVersion))
}
var cachedKernelVersion *Version
func init() {
if res, err := CurrentKernelVersion(); err == nil {
cachedKernelVersion = res
}
}
// CurrentKernelVersion returns the current kernel version.
func CurrentKernelVersion() (*Version, error) {
if cachedKernelVersion != nil {
return cachedKernelVersion, nil
}
// We need extra checks for Debian and Ubuntu as they modify
// the kernel version patch number for compatibilty with
// out-of-tree modules. Linux perf tools do the same for Ubuntu
// systems: https://github.com/torvalds/linux/commit/d18acd15c
//
// See also:
// https://kernel-handbook.alioth.debian.org/ch-versions.html
// https://wiki.ubuntu.com/Kernel/FAQ
version, err := currentVersionUbuntu()
if err == nil {
return &version, nil
}
version, err = currentVersionDebian()
if err == nil {
return &version, nil
}
version, err = currentVersionUname()
if err != nil {
return nil, err
}
return &version, nil
}