github.com/dolfly/pty@v1.2.1/pty_freebsd.go (about) 1 //go:build freebsd 2 //+build freebsd 3 4 package pty 5 6 import ( 7 "errors" 8 "os" 9 "syscall" 10 "unsafe" 11 ) 12 13 func posixOpenpt(oflag int) (fd int, err error) { 14 r0, _, e1 := syscall.Syscall(syscall.SYS_POSIX_OPENPT, uintptr(oflag), 0, 0) 15 fd = int(r0) 16 if e1 != 0 { 17 err = e1 18 } 19 return fd, err 20 } 21 22 func open() (pty, tty *os.File, err error) { 23 fd, err := posixOpenpt(syscall.O_RDWR | syscall.O_CLOEXEC) 24 if err != nil { 25 return nil, nil, err 26 } 27 p := os.NewFile(uintptr(fd), "/dev/pts") 28 // In case of error after this point, make sure we close the pts fd. 29 defer func() { 30 if err != nil { 31 _ = p.Close() // Best effort. 32 } 33 }() 34 35 sname, err := ptsname(p) 36 if err != nil { 37 return nil, nil, err 38 } 39 40 t, err := os.OpenFile("/dev/"+sname, os.O_RDWR, 0) 41 if err != nil { 42 return nil, nil, err 43 } 44 return p, t, nil 45 } 46 47 func isptmaster(fd uintptr) (bool, error) { 48 err := ioctl(fd, syscall.TIOCPTMASTER, 0) 49 return err == nil, err 50 } 51 52 var ( 53 emptyFiodgnameArg fiodgnameArg 54 ioctlFIODGNAME = _IOW('f', 120, unsafe.Sizeof(emptyFiodgnameArg)) 55 ) 56 57 func ptsname(f *os.File) (string, error) { 58 master, err := isptmaster(f.Fd()) 59 if err != nil { 60 return "", err 61 } 62 if !master { 63 return "", syscall.EINVAL 64 } 65 66 const n = _C_SPECNAMELEN + 1 67 var ( 68 buf = make([]byte, n) 69 arg = fiodgnameArg{Len: n, Buf: (*byte)(unsafe.Pointer(&buf[0]))} 70 ) 71 if err := ioctl(f.Fd(), ioctlFIODGNAME, uintptr(unsafe.Pointer(&arg))); err != nil { 72 return "", err 73 } 74 75 for i, c := range buf { 76 if c == 0 { 77 return string(buf[:i]), nil 78 } 79 } 80 return "", errors.New("FIODGNAME string not NUL-terminated") 81 }