pty_netbsd.go 1.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. //go:build netbsd
  2. // +build netbsd
  3. package pty
  4. import (
  5. "errors"
  6. "os"
  7. "syscall"
  8. "unsafe"
  9. )
  10. func open() (pty, tty *os.File, err error) {
  11. p, err := os.OpenFile("/dev/ptmx", os.O_RDWR, 0)
  12. if err != nil {
  13. return nil, nil, err
  14. }
  15. // In case of error after this point, make sure we close the ptmx fd.
  16. defer func() {
  17. if err != nil {
  18. _ = p.Close() // Best effort.
  19. }
  20. }()
  21. sname, err := ptsname(p)
  22. if err != nil {
  23. return nil, nil, err
  24. }
  25. if err := grantpt(p); err != nil {
  26. return nil, nil, err
  27. }
  28. // In NetBSD unlockpt() does nothing, so it isn't called here.
  29. t, err := os.OpenFile(sname, os.O_RDWR|syscall.O_NOCTTY, 0)
  30. if err != nil {
  31. return nil, nil, err
  32. }
  33. return p, t, nil
  34. }
  35. func ptsname(f *os.File) (string, error) {
  36. /*
  37. * from ptsname(3): The ptsname() function is equivalent to:
  38. * struct ptmget pm;
  39. * ioctl(fd, TIOCPTSNAME, &pm) == -1 ? NULL : pm.sn;
  40. */
  41. var ptm ptmget
  42. if err := ioctl(f.Fd(), uintptr(ioctl_TIOCPTSNAME), uintptr(unsafe.Pointer(&ptm))); err != nil {
  43. return "", err
  44. }
  45. name := make([]byte, len(ptm.Sn))
  46. for i, c := range ptm.Sn {
  47. name[i] = byte(c)
  48. if c == 0 {
  49. return string(name[:i]), nil
  50. }
  51. }
  52. return "", errors.New("TIOCPTSNAME string not NUL-terminated")
  53. }
  54. func grantpt(f *os.File) error {
  55. /*
  56. * from grantpt(3): Calling grantpt() is equivalent to:
  57. * ioctl(fd, TIOCGRANTPT, 0);
  58. */
  59. return ioctl(f.Fd(), uintptr(ioctl_TIOCGRANTPT), 0)
  60. }