// Copyright 2024 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package unix import ( "runtime" "sync" "syscall" "unsafe" ) //go:linkname procUname libc_uname var procUname uintptr // utsname represents the fields of a struct utsname defined in . type utsname struct { Sysname [257]byte Nodename [257]byte Release [257]byte Version [257]byte Machine [257]byte } // KernelVersion returns major and minor kernel version numbers // parsed from the syscall.Uname's Version field, or (0, 0) if the // version can't be obtained or parsed. func KernelVersion() (major int, minor int) { var un utsname _, _, errno := rawSyscall6(uintptr(unsafe.Pointer(&procUname)), 1, uintptr(unsafe.Pointer(&un)), 0, 0, 0, 0, 0) if errno != 0 { return 0, 0 } // The version string is in the form "...." // on Solaris: https://blogs.oracle.com/solaris/post/whats-in-a-uname- // Therefore, we use the Version field on Solaris when available. ver := un.Version[:] if runtime.GOOS == "illumos" { // Illumos distributions use different formats without a parsable // and unified pattern for the Version field while Release level // string is guaranteed to be in x.y or x.y.z format regardless of // whether the kernel is Solaris or illumos. ver = un.Release[:] } parseNext := func() (n int) { for i, c := range ver { if c == '.' { ver = ver[i+1:] return } if '0' <= c && c <= '9' { n = n*10 + int(c-'0') } } ver = nil return } major = parseNext() minor = parseNext() return } // SupportSockNonblockCloexec tests if SOCK_NONBLOCK and SOCK_CLOEXEC are supported // for socket() system call, returns true if affirmative. var SupportSockNonblockCloexec = sync.OnceValue(func() bool { // First test if socket() supports SOCK_NONBLOCK and SOCK_CLOEXEC directly. s, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_STREAM|syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC, 0) if err == nil { syscall.Close(s) return true } if err != syscall.EPROTONOSUPPORT && err != syscall.EINVAL { // Something wrong with socket(), fall back to checking the kernel version. major, minor := KernelVersion() if runtime.GOOS == "illumos" { return major > 5 || (major == 5 && minor >= 11) // minimal requirement is SunOS 5.11 } return major > 11 || (major == 11 && minor >= 4) } return false }) // SupportAccept4 tests whether accept4 system call is available. var SupportAccept4 = sync.OnceValue(func() bool { for { // Test if the accept4() is available. _, _, err := syscall.Accept4(0, syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC) if err == syscall.EINTR { continue } return err != syscall.ENOSYS } }) // SupportTCPKeepAliveIdleIntvlCNT determines whether the TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT // are available by checking the kernel version for Solaris 11.4. var SupportTCPKeepAliveIdleIntvlCNT = sync.OnceValue(func() bool { major, minor := KernelVersion() return major > 11 || (major == 11 && minor >= 4) })