kernel_version_solaris.mx raw

   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