psnotify.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. // Copyright (c) 2012 VMware, Inc.
  2. // +build darwin freebsd netbsd openbsd linux
  3. package psnotify
  4. import (
  5. "errors"
  6. "fmt"
  7. )
  8. type ProcEventFork struct {
  9. ParentPid int // Pid of the process that called fork()
  10. ChildPid int // Child process pid created by fork()
  11. }
  12. type ProcEventExec struct {
  13. Pid int // Pid of the process that called exec()
  14. }
  15. type ProcEventExit struct {
  16. Pid int // Pid of the process that called exit()
  17. }
  18. type watch struct {
  19. flags uint32 // Saved value of Watch() flags param
  20. }
  21. type eventListener interface {
  22. close() error // Watch.Close() closes the OS specific listener
  23. }
  24. type Watcher struct {
  25. listener eventListener // OS specifics (kqueue or netlink)
  26. watches map[int]*watch // Map of watched process ids
  27. Error chan error // Errors are sent on this channel
  28. Fork chan *ProcEventFork // Fork events are sent on this channel
  29. Exec chan *ProcEventExec // Exec events are sent on this channel
  30. Exit chan *ProcEventExit // Exit events are sent on this channel
  31. done chan bool // Used to stop the readEvents() goroutine
  32. isClosed bool // Set to true when Close() is first called
  33. }
  34. // Initialize event listener and channels
  35. func NewWatcher() (*Watcher, error) {
  36. listener, err := createListener()
  37. if err != nil {
  38. return nil, err
  39. }
  40. w := &Watcher{
  41. listener: listener,
  42. watches: make(map[int]*watch),
  43. Fork: make(chan *ProcEventFork),
  44. Exec: make(chan *ProcEventExec),
  45. Exit: make(chan *ProcEventExit),
  46. Error: make(chan error),
  47. done: make(chan bool, 1),
  48. }
  49. go w.readEvents()
  50. return w, nil
  51. }
  52. // Close event channels when done message is received
  53. func (w *Watcher) finish() {
  54. close(w.Fork)
  55. close(w.Exec)
  56. close(w.Exit)
  57. close(w.Error)
  58. }
  59. // Closes the OS specific event listener,
  60. // removes all watches and closes all event channels.
  61. func (w *Watcher) Close() error {
  62. if w.isClosed {
  63. return nil
  64. }
  65. w.isClosed = true
  66. for pid := range w.watches {
  67. w.RemoveWatch(pid)
  68. }
  69. w.done <- true
  70. w.listener.close()
  71. return nil
  72. }
  73. // Add pid to the watched process set.
  74. // The flags param is a bitmask of process events to capture,
  75. // must be one or more of: PROC_EVENT_FORK, PROC_EVENT_EXEC, PROC_EVENT_EXIT
  76. func (w *Watcher) Watch(pid int, flags uint32) error {
  77. if w.isClosed {
  78. return errors.New("psnotify watcher is closed")
  79. }
  80. watchEntry, found := w.watches[pid]
  81. if found {
  82. watchEntry.flags |= flags
  83. } else {
  84. if err := w.register(pid, flags); err != nil {
  85. return err
  86. }
  87. w.watches[pid] = &watch{flags: flags}
  88. }
  89. return nil
  90. }
  91. // Remove pid from the watched process set.
  92. func (w *Watcher) RemoveWatch(pid int) error {
  93. _, ok := w.watches[pid]
  94. if !ok {
  95. msg := fmt.Sprintf("watch for pid=%d does not exist", pid)
  96. return errors.New(msg)
  97. }
  98. delete(w.watches, pid)
  99. return w.unregister(pid)
  100. }
  101. // Internal helper to check if there is a message on the "done" channel.
  102. // The "done" message is sent by the Close() method; when received here,
  103. // the Watcher.finish method is called to close all channels and return
  104. // true - in which case the caller should break from the readEvents loop.
  105. func (w *Watcher) isDone() bool {
  106. var done bool
  107. select {
  108. case done = <-w.done:
  109. w.finish()
  110. default:
  111. }
  112. return done
  113. }