github.com/geraldss/go/src@v0.0.0-20210511222824-ac7d0ebfc235/os/signal/internal/pty/pty.go (about)

     1  // Copyright 2017 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // +build aix darwin dragonfly freebsd linux,!android netbsd openbsd
     6  // +build cgo
     7  
     8  // Package pty is a simple pseudo-terminal package for Unix systems,
     9  // implemented by calling C functions via cgo.
    10  // This is only used for testing the os/signal package.
    11  package pty
    12  
    13  /*
    14  #define _XOPEN_SOURCE 600
    15  #include <fcntl.h>
    16  #include <stdlib.h>
    17  #include <unistd.h>
    18  */
    19  import "C"
    20  
    21  import (
    22  	"fmt"
    23  	"os"
    24  	"syscall"
    25  )
    26  
    27  type PtyError struct {
    28  	FuncName    string
    29  	ErrorString string
    30  	Errno       syscall.Errno
    31  }
    32  
    33  func ptyError(name string, err error) *PtyError {
    34  	return &PtyError{name, err.Error(), err.(syscall.Errno)}
    35  }
    36  
    37  func (e *PtyError) Error() string {
    38  	return fmt.Sprintf("%s: %s", e.FuncName, e.ErrorString)
    39  }
    40  
    41  func (e *PtyError) Unwrap() error { return e.Errno }
    42  
    43  // Open returns a control pty and the name of the linked process tty.
    44  func Open() (pty *os.File, processTTY string, err error) {
    45  	m, err := C.posix_openpt(C.O_RDWR)
    46  	if err != nil {
    47  		return nil, "", ptyError("posix_openpt", err)
    48  	}
    49  	if _, err := C.grantpt(m); err != nil {
    50  		C.close(m)
    51  		return nil, "", ptyError("grantpt", err)
    52  	}
    53  	if _, err := C.unlockpt(m); err != nil {
    54  		C.close(m)
    55  		return nil, "", ptyError("unlockpt", err)
    56  	}
    57  	processTTY = C.GoString(C.ptsname(m))
    58  	return os.NewFile(uintptr(m), "pty"), processTTY, nil
    59  }