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  }