pty_freebsd.go 1.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. package pty
  2. import (
  3. "errors"
  4. "os"
  5. "syscall"
  6. "unsafe"
  7. )
  8. func posix_openpt(oflag int) (fd int, err error) {
  9. r0, _, e1 := syscall.Syscall(syscall.SYS_POSIX_OPENPT, uintptr(oflag), 0, 0)
  10. fd = int(r0)
  11. if e1 != 0 {
  12. err = e1
  13. }
  14. return
  15. }
  16. func open() (pty, tty *os.File, err error) {
  17. fd, err := posix_openpt(syscall.O_RDWR | syscall.O_CLOEXEC)
  18. if err != nil {
  19. return nil, nil, err
  20. }
  21. p := os.NewFile(uintptr(fd), "/dev/pts")
  22. sname, err := ptsname(p)
  23. if err != nil {
  24. return nil, nil, err
  25. }
  26. t, err := os.OpenFile("/dev/"+sname, os.O_RDWR, 0)
  27. if err != nil {
  28. return nil, nil, err
  29. }
  30. return p, t, nil
  31. }
  32. func isptmaster(fd uintptr) (bool, error) {
  33. err := ioctl(fd, syscall.TIOCPTMASTER, 0)
  34. return err == nil, err
  35. }
  36. var (
  37. emptyFiodgnameArg fiodgnameArg
  38. ioctl_FIODGNAME = _IOW('f', 120, unsafe.Sizeof(emptyFiodgnameArg))
  39. )
  40. func ptsname(f *os.File) (string, error) {
  41. master, err := isptmaster(f.Fd())
  42. if err != nil {
  43. return "", err
  44. }
  45. if !master {
  46. return "", syscall.EINVAL
  47. }
  48. const n = _C_SPECNAMELEN + 1
  49. var (
  50. buf = make([]byte, n)
  51. arg = fiodgnameArg{Len: n, Buf: (*byte)(unsafe.Pointer(&buf[0]))}
  52. )
  53. err = ioctl(f.Fd(), ioctl_FIODGNAME, uintptr(unsafe.Pointer(&arg)))
  54. if err != nil {
  55. return "", err
  56. }
  57. for i, c := range buf {
  58. if c == 0 {
  59. return string(buf[:i]), nil
  60. }
  61. }
  62. return "", errors.New("FIODGNAME string not NUL-terminated")
  63. }