github.com/jlowellwofford/u-root@v1.0.0/pkg/pty/pty_linux.go (about) 1 // Copyright 2015-2017 the u-root 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 // Package pty provides basic pty support. 6 // It implments much of exec.Command 7 // but the Start() function starts two goroutines that relay the 8 // data for Stdin, Stdout, and Stdout such that proper kernel pty 9 // processing is done. We did not simply embed an exec.Command 10 // as we can no guarantee that we can implement all aspects of it 11 // for all time to come. 12 package pty 13 14 import ( 15 "fmt" 16 "os" 17 "syscall" 18 "unsafe" 19 20 "github.com/u-root/u-root/pkg/termios" 21 ) 22 23 // pty support. We used to import github.com/kr/pty but what we need is not that complex. 24 // Thanks to keith rarick for these functions. 25 func New() (*Pty, error) { 26 tty, err := termios.New() 27 if err != nil { 28 return nil, err 29 } 30 restorer, err := tty.Get() 31 if err != nil { 32 return nil, err 33 } 34 ptm, err := os.OpenFile("/dev/ptmx", os.O_RDWR, 0) 35 if err != nil { 36 return nil, err 37 } 38 39 if err := ptsunlock(ptm); err != nil { 40 return nil, err 41 } 42 43 sname, err := ptsname(ptm) 44 if err != nil { 45 return nil, err 46 } 47 48 // It can take a non-zero time for a pts to appear, it seems. 49 // Ten tries is reported to be far more than enough. 50 for i := 0; i < 10; i++ { 51 _, err := os.Stat(sname) 52 if err == nil { 53 break 54 } 55 } 56 pts, err := os.OpenFile(sname, os.O_RDWR|syscall.O_NOCTTY, 0) 57 if err != nil { 58 return nil, err 59 } 60 return &Pty{Ptm: ptm, Pts: pts, Sname: sname, Kid: -1, TTY: tty, Restorer: restorer}, nil 61 } 62 63 func ptsname(f *os.File) (string, error) { 64 var n uintptr 65 _, _, err := syscall.Syscall(syscall.SYS_IOCTL, f.Fd(), syscall.TIOCGPTN, uintptr(unsafe.Pointer(&n))) 66 if err != 0 { 67 return "", err 68 } 69 return fmt.Sprintf("/dev/pts/%d", n), nil 70 } 71 72 func ptsunlock(f *os.File) error { 73 var u uintptr 74 // use TIOCSPTLCK with a zero valued arg to clear the slave pty lock 75 _, _, err := syscall.Syscall(syscall.SYS_IOCTL, f.Fd(), syscall.TIOCSPTLCK, uintptr(unsafe.Pointer(&u))) 76 if err != 0 { 77 return err 78 } 79 return nil 80 }