Source file src/internal/syscall/unix/kernel_version_solaris.go

     1  // Copyright 2024 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package unix
     6  
     7  import (
     8  	"runtime"
     9  	"sync"
    10  	"syscall"
    11  	"unsafe"
    12  )
    13  
    14  //go:linkname procUname libc_uname
    15  
    16  var procUname uintptr
    17  
    18  // utsname represents the fields of a struct utsname defined in <sys/utsname.h>.
    19  type utsname struct {
    20  	Sysname  [257]byte
    21  	Nodename [257]byte
    22  	Release  [257]byte
    23  	Version  [257]byte
    24  	Machine  [257]byte
    25  }
    26  
    27  // KernelVersion returns major and minor kernel version numbers
    28  // parsed from the syscall.Uname's Version field, or (0, 0) if the
    29  // version can't be obtained or parsed.
    30  func KernelVersion() (major int, minor int) {
    31  	var un utsname
    32  	_, _, errno := rawSyscall6(uintptr(unsafe.Pointer(&procUname)), 1, uintptr(unsafe.Pointer(&un)), 0, 0, 0, 0, 0)
    33  	if errno != 0 {
    34  		return 0, 0
    35  	}
    36  
    37  	// The version string is in the form "<version>.<update>.<sru>.<build>.<reserved>"
    38  	// on Solaris: https://blogs.oracle.com/solaris/post/whats-in-a-uname-
    39  	// Therefore, we use the Version field on Solaris when available.
    40  	ver := un.Version[:]
    41  	if runtime.GOOS == "illumos" {
    42  		// Illumos distributions use different formats without a parsable
    43  		// and unified pattern for the Version field while Release level
    44  		// string is guaranteed to be in x.y or x.y.z format regardless of
    45  		// whether the kernel is Solaris or illumos.
    46  		ver = un.Release[:]
    47  	}
    48  
    49  	parseNext := func() (n int) {
    50  		for i, c := range ver {
    51  			if c == '.' {
    52  				ver = ver[i+1:]
    53  				return
    54  			}
    55  			if '0' <= c && c <= '9' {
    56  				n = n*10 + int(c-'0')
    57  			}
    58  		}
    59  		ver = nil
    60  		return
    61  	}
    62  
    63  	major = parseNext()
    64  	minor = parseNext()
    65  
    66  	return
    67  }
    68  
    69  // SupportSockNonblockCloexec tests if SOCK_NONBLOCK and SOCK_CLOEXEC are supported
    70  // for socket() system call, returns true if affirmative.
    71  var SupportSockNonblockCloexec = sync.OnceValue(func() bool {
    72  	// First test if socket() supports SOCK_NONBLOCK and SOCK_CLOEXEC directly.
    73  	s, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_STREAM|syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC, 0)
    74  	if err == nil {
    75  		syscall.Close(s)
    76  		return true
    77  	}
    78  	if err != syscall.EPROTONOSUPPORT && err != syscall.EINVAL {
    79  		// Something wrong with socket(), fall back to checking the kernel version.
    80  		major, minor := KernelVersion()
    81  		if runtime.GOOS == "illumos" {
    82  			return major > 5 || (major == 5 && minor >= 11) // minimal requirement is SunOS 5.11
    83  		}
    84  		return major > 11 || (major == 11 && minor >= 4)
    85  	}
    86  	return false
    87  })
    88  
    89  // SupportAccept4 tests whether accept4 system call is available.
    90  var SupportAccept4 = sync.OnceValue(func() bool {
    91  	for {
    92  		// Test if the accept4() is available.
    93  		_, _, err := syscall.Accept4(0, syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC)
    94  		if err == syscall.EINTR {
    95  			continue
    96  		}
    97  		return err != syscall.ENOSYS
    98  	}
    99  })
   100  
   101  // SupportTCPKeepAliveIdleIntvlCNT determines whether the TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT
   102  // are available by checking the kernel version for Solaris 11.4.
   103  var SupportTCPKeepAliveIdleIntvlCNT = sync.OnceValue(func() bool {
   104  	major, minor := KernelVersion()
   105  	return major > 11 || (major == 11 && minor >= 4)
   106  })
   107  

View as plain text