process_posix.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. // +build linux freebsd openbsd darwin
  2. package process
  3. import (
  4. "context"
  5. "os"
  6. "os/user"
  7. "path/filepath"
  8. "strconv"
  9. "strings"
  10. "syscall"
  11. "golang.org/x/sys/unix"
  12. )
  13. // POSIX
  14. func getTerminalMap() (map[uint64]string, error) {
  15. ret := make(map[uint64]string)
  16. var termfiles []string
  17. d, err := os.Open("/dev")
  18. if err != nil {
  19. return nil, err
  20. }
  21. defer d.Close()
  22. devnames, err := d.Readdirnames(-1)
  23. if err != nil {
  24. return nil, err
  25. }
  26. for _, devname := range devnames {
  27. if strings.HasPrefix(devname, "/dev/tty") {
  28. termfiles = append(termfiles, "/dev/tty/"+devname)
  29. }
  30. }
  31. var ptsnames []string
  32. ptsd, err := os.Open("/dev/pts")
  33. if err != nil {
  34. ptsnames, _ = filepath.Glob("/dev/ttyp*")
  35. if ptsnames == nil {
  36. return nil, err
  37. }
  38. }
  39. defer ptsd.Close()
  40. if ptsnames == nil {
  41. defer ptsd.Close()
  42. ptsnames, err = ptsd.Readdirnames(-1)
  43. if err != nil {
  44. return nil, err
  45. }
  46. for _, ptsname := range ptsnames {
  47. termfiles = append(termfiles, "/dev/pts/"+ptsname)
  48. }
  49. } else {
  50. termfiles = ptsnames
  51. }
  52. for _, name := range termfiles {
  53. stat := unix.Stat_t{}
  54. if err = unix.Stat(name, &stat); err != nil {
  55. return nil, err
  56. }
  57. rdev := uint64(stat.Rdev)
  58. ret[rdev] = strings.Replace(name, "/dev", "", -1)
  59. }
  60. return ret, nil
  61. }
  62. // SendSignal sends a unix.Signal to the process.
  63. // Currently, SIGSTOP, SIGCONT, SIGTERM and SIGKILL are supported.
  64. func (p *Process) SendSignal(sig syscall.Signal) error {
  65. return p.SendSignalWithContext(context.Background(), sig)
  66. }
  67. func (p *Process) SendSignalWithContext(ctx context.Context, sig syscall.Signal) error {
  68. process, err := os.FindProcess(int(p.Pid))
  69. if err != nil {
  70. return err
  71. }
  72. err = process.Signal(sig)
  73. if err != nil {
  74. return err
  75. }
  76. return nil
  77. }
  78. // Suspend sends SIGSTOP to the process.
  79. func (p *Process) Suspend() error {
  80. return p.SuspendWithContext(context.Background())
  81. }
  82. func (p *Process) SuspendWithContext(ctx context.Context) error {
  83. return p.SendSignal(unix.SIGSTOP)
  84. }
  85. // Resume sends SIGCONT to the process.
  86. func (p *Process) Resume() error {
  87. return p.ResumeWithContext(context.Background())
  88. }
  89. func (p *Process) ResumeWithContext(ctx context.Context) error {
  90. return p.SendSignal(unix.SIGCONT)
  91. }
  92. // Terminate sends SIGTERM to the process.
  93. func (p *Process) Terminate() error {
  94. return p.TerminateWithContext(context.Background())
  95. }
  96. func (p *Process) TerminateWithContext(ctx context.Context) error {
  97. return p.SendSignal(unix.SIGTERM)
  98. }
  99. // Kill sends SIGKILL to the process.
  100. func (p *Process) Kill() error {
  101. return p.KillWithContext(context.Background())
  102. }
  103. func (p *Process) KillWithContext(ctx context.Context) error {
  104. return p.SendSignal(unix.SIGKILL)
  105. }
  106. // Username returns a username of the process.
  107. func (p *Process) Username() (string, error) {
  108. return p.UsernameWithContext(context.Background())
  109. }
  110. func (p *Process) UsernameWithContext(ctx context.Context) (string, error) {
  111. uids, err := p.Uids()
  112. if err != nil {
  113. return "", err
  114. }
  115. if len(uids) > 0 {
  116. u, err := user.LookupId(strconv.Itoa(int(uids[0])))
  117. if err != nil {
  118. return "", err
  119. }
  120. return u.Username, nil
  121. }
  122. return "", nil
  123. }