lock_file.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. package daemon
  2. import (
  3. "errors"
  4. "fmt"
  5. "os"
  6. )
  7. var (
  8. // ErrWouldBlock indicates on locking pid-file by another process.
  9. ErrWouldBlock = errors.New("daemon: Resource temporarily unavailable")
  10. )
  11. // LockFile wraps *os.File and provide functions for locking of files.
  12. type LockFile struct {
  13. *os.File
  14. }
  15. // NewLockFile returns a new LockFile with the given File.
  16. func NewLockFile(file *os.File) *LockFile {
  17. return &LockFile{file}
  18. }
  19. // CreatePidFile opens the named file, applies exclusive lock and writes
  20. // current process id to file.
  21. func CreatePidFile(name string, perm os.FileMode) (lock *LockFile, err error) {
  22. if lock, err = OpenLockFile(name, perm); err != nil {
  23. return
  24. }
  25. if err = lock.Lock(); err != nil {
  26. lock.Remove()
  27. return
  28. }
  29. if err = lock.WritePid(); err != nil {
  30. lock.Remove()
  31. }
  32. return
  33. }
  34. // OpenLockFile opens the named file with flags os.O_RDWR|os.O_CREATE and specified perm.
  35. // If successful, function returns LockFile for opened file.
  36. func OpenLockFile(name string, perm os.FileMode) (lock *LockFile, err error) {
  37. var file *os.File
  38. if file, err = os.OpenFile(name, os.O_RDWR|os.O_CREATE, perm); err == nil {
  39. lock = &LockFile{file}
  40. }
  41. return
  42. }
  43. // Lock apply exclusive lock on an open file. If file already locked, returns error.
  44. func (file *LockFile) Lock() error {
  45. return lockFile(file.Fd())
  46. }
  47. // Unlock remove exclusive lock on an open file.
  48. func (file *LockFile) Unlock() error {
  49. return unlockFile(file.Fd())
  50. }
  51. // ReadPidFile reads process id from file with give name and returns pid.
  52. // If unable read from a file, returns error.
  53. func ReadPidFile(name string) (pid int, err error) {
  54. var file *os.File
  55. if file, err = os.OpenFile(name, os.O_RDONLY, 0640); err != nil {
  56. return
  57. }
  58. defer file.Close()
  59. lock := &LockFile{file}
  60. pid, err = lock.ReadPid()
  61. return
  62. }
  63. // WritePid writes current process id to an open file.
  64. func (file *LockFile) WritePid() (err error) {
  65. if _, err = file.Seek(0, os.SEEK_SET); err != nil {
  66. return
  67. }
  68. var fileLen int
  69. if fileLen, err = fmt.Fprint(file, os.Getpid()); err != nil {
  70. return
  71. }
  72. if err = file.Truncate(int64(fileLen)); err != nil {
  73. return
  74. }
  75. err = file.Sync()
  76. return
  77. }
  78. // ReadPid reads process id from file and returns pid.
  79. // If unable read from a file, returns error.
  80. func (file *LockFile) ReadPid() (pid int, err error) {
  81. if _, err = file.Seek(0, os.SEEK_SET); err != nil {
  82. return
  83. }
  84. _, err = fmt.Fscan(file, &pid)
  85. return
  86. }
  87. // Remove removes lock, closes and removes an open file.
  88. func (file *LockFile) Remove() error {
  89. defer file.Close()
  90. if err := file.Unlock(); err != nil {
  91. return err
  92. }
  93. return os.Remove(file.Name())
  94. }