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