Errno and the Three Syscall Layers
Trigger a real error, pull the raw errno out of the chain, and match it with a portable sentinel. Runs on Linux and macOS with only the standard library.
package main
import (
"errors"
"fmt"
"os"
"syscall"
)
func main() {
// Top layer: os. Portable and ergonomic.
_, err := os.Open("/no/such/file")
fmt.Println("os.Open error:", err)
// os.Open error: open /no/such/file: no such file or directory
// Dig the raw errno out of the wrapped error chain.
var errno syscall.Errno
if errors.As(err, &errno) {
fmt.Printf("errno: %d (%s)\n", uintptr(errno), errno)
// errno: 2 (no such file or directory)
fmt.Println("is ENOENT:", errno == syscall.ENOENT) // is ENOENT: true
}
// Prefer portable sentinels over comparing raw errno numbers.
fmt.Println("matches os.ErrNotExist:", errors.Is(err, os.ErrNotExist))
// matches os.ErrNotExist: true
// Raw layer: syscall.Open hands back a file descriptor (an int), not an *os.File.
fd, err := syscall.Open("/dev/null", syscall.O_RDONLY, 0)
if err != nil {
fmt.Println("syscall.Open:", err)
return
}
defer syscall.Close(fd)
fmt.Println("raw fd for /dev/null:", fd) // raw fd for /dev/null: 3
}Save the code as main.go and run it:
go run main.goExpected output:
os.Open error: open /no/such/file: no such file or directory
errno: 2 (no such file or directory)
is ENOENT: true
matches os.ErrNotExist: true
raw fd for /dev/null: 3The raw file descriptor number may differ depending on what's already open.