github.com/minio/madmin-go@v1.7.5/kernel/kernel.go (about) 1 // 2 // MinIO Object Storage (c) 2022 MinIO, Inc. 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 // 16 17 //go:build linux 18 // +build linux 19 20 package kernel 21 22 import ( 23 "fmt" 24 "io/ioutil" 25 "regexp" 26 "strconv" 27 "strings" 28 "syscall" 29 ) 30 31 var versionRegex = regexp.MustCompile(`^(\d+)\.(\d+).(\d+).*$`) 32 33 // VersionFromRelease converts a release string with format 34 // 4.4.2[-1] to a kernel version number in LINUX_VERSION_CODE format. 35 // That is, for kernel "a.b.c", the version number will be (a<<16 + b<<8 + c) 36 func VersionFromRelease(releaseString string) (uint32, error) { 37 versionParts := versionRegex.FindStringSubmatch(releaseString) 38 if len(versionParts) != 4 { 39 return 0, fmt.Errorf("got invalid release version %q (expected format '4.3.2-1')", releaseString) 40 } 41 major, err := strconv.Atoi(versionParts[1]) 42 if err != nil { 43 return 0, err 44 } 45 46 minor, err := strconv.Atoi(versionParts[2]) 47 if err != nil { 48 return 0, err 49 } 50 51 patch, err := strconv.Atoi(versionParts[3]) 52 if err != nil { 53 return 0, err 54 } 55 return Version(major, minor, patch), nil 56 } 57 58 // Version implements KERNEL_VERSION equivalent macro 59 // #define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + ((c) > 255 ? 255 : (c))) 60 func Version(major, minor, patch int) uint32 { 61 if patch > 255 { 62 patch = 255 63 } 64 out := major<<16 + minor<<8 + patch 65 return uint32(out) 66 } 67 68 func currentReleaseUname() (string, error) { 69 var buf syscall.Utsname 70 if err := syscall.Uname(&buf); err != nil { 71 return "", err 72 } 73 releaseString := strings.Trim(utsnameStr(buf.Release[:]), "\x00") 74 return releaseString, nil 75 } 76 77 func currentReleaseUbuntu() (string, error) { 78 procVersion, err := ioutil.ReadFile("/proc/version_signature") 79 if err != nil { 80 return "", err 81 } 82 var u1, u2, releaseString string 83 _, err = fmt.Sscanf(string(procVersion), "%s %s %s", &u1, &u2, &releaseString) 84 if err != nil { 85 return "", err 86 } 87 return releaseString, nil 88 } 89 90 var debianVersionRegex = regexp.MustCompile(`.* SMP Debian (\d+\.\d+.\d+-\d+)(?:\+[[:alnum:]]*)?.*`) 91 92 func parseDebianRelease(str string) (string, error) { 93 match := debianVersionRegex.FindStringSubmatch(str) 94 if len(match) != 2 { 95 return "", fmt.Errorf("failed to parse kernel version from /proc/version: %s", str) 96 } 97 return match[1], nil 98 } 99 100 func currentReleaseDebian() (string, error) { 101 procVersion, err := ioutil.ReadFile("/proc/version") 102 if err != nil { 103 return "", fmt.Errorf("error reading /proc/version: %s", err) 104 } 105 106 return parseDebianRelease(string(procVersion)) 107 } 108 109 // CurrentRelease returns the current kernel release ensuring that 110 // ubuntu and debian release numbers are accurate. 111 func CurrentRelease() (string, error) { 112 // We need extra checks for Debian and Ubuntu as they modify 113 // the kernel version patch number for compatibility with 114 // out-of-tree modules. Linux perf tools do the same for Ubuntu 115 // systems: https://github.com/torvalds/linux/commit/d18acd15c 116 // 117 // See also: 118 // https://kernel-team.pages.debian.net/kernel-handbook/ch-versions.html 119 // https://wiki.ubuntu.com/Kernel/FAQ 120 version, err := currentReleaseUbuntu() 121 if err == nil { 122 return version, nil 123 } 124 version, err = currentReleaseDebian() 125 if err == nil { 126 return version, nil 127 } 128 return currentReleaseUname() 129 } 130 131 // CurrentVersion returns the current kernel version in 132 // LINUX_VERSION_CODE format (see VersionFromRelease()) 133 func CurrentVersion() (uint32, error) { 134 release, err := CurrentRelease() 135 if err == nil { 136 return VersionFromRelease(release) 137 } 138 return 0, err 139 }