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