github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/spotty/spotty_nix.go (about) 1 // Copyright 2015 Keybase, Inc. All rights reserved. Use of 2 // this source code is governed by the included BSD license. 3 4 //go:build darwin || dragonfly || freebsd || linux || nacl || netbsd || openbsd || solaris 5 // +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris 6 7 package spotty 8 9 import ( 10 "os" 11 "path/filepath" 12 "regexp" 13 "syscall" 14 ) 15 16 func sameFile(ss1 *syscall.Stat_t, fi os.FileInfo) bool { 17 if ss2, ok := fi.Sys().(*syscall.Stat_t); ok { 18 return ss1.Dev == ss2.Dev && ss1.Rdev == ss2.Rdev && ss1.Ino == ss2.Ino 19 } 20 return false 21 } 22 23 // Discover which named TTY we have open as FD=0. Will return empty string if nothing 24 // was found, and a non-nil error if there was a problem. Will noop on Windows. 25 func Discover() (string, error) { 26 var sstat syscall.Stat_t 27 if err := syscall.Fstat(0, &sstat); err != nil { 28 return "", err 29 } 30 res, err := findFileIn(&sstat, "/dev", regexp.MustCompile(`^tty[A-Za-z0-9]+$`)) 31 if err != nil { 32 return "", err 33 } 34 if len(res) > 0 { 35 return res, nil 36 } 37 res, err = findFileIn(&sstat, "/dev/pts", regexp.MustCompile(`^[0-9]+$`)) 38 return res, err 39 } 40 41 func findFileIn(ss *syscall.Stat_t, dir string, re *regexp.Regexp) (string, error) { 42 v, err := os.ReadDir(dir) 43 if err != nil { 44 if _, ok := err.(*os.PathError); ok { 45 return "", nil 46 } 47 return "", err 48 } 49 for _, fi := range v { 50 if !re.MatchString(fi.Name()) { 51 continue 52 } 53 info, err := fi.Info() 54 if err != nil { 55 return "", err 56 } 57 if sameFile(ss, info) { 58 return filepath.Join(dir, fi.Name()), nil 59 } 60 } 61 return "", nil 62 }