github.com/cloud-foundations/dominator@v0.0.0-20221004181915-6e4fee580046/lib/fsutil/watchFile.go (about) 1 package fsutil 2 3 import ( 4 "io" 5 "os" 6 "syscall" 7 "time" 8 9 "github.com/Cloud-Foundations/Dominator/lib/log" 10 ) 11 12 var stopped bool 13 14 func watchFile(pathname string, logger log.Logger) <-chan io.ReadCloser { 15 channel := make(chan io.ReadCloser, 1) 16 if !watchFileWithFsNotify(pathname, channel, logger) { 17 go watchFileForever(pathname, channel, logger) 18 } 19 return channel 20 } 21 22 func watchFileStop() { 23 if !watchFileStopWithFsNotify() { 24 stopped = true 25 } 26 } 27 28 func watchFileForever(pathname string, channel chan<- io.ReadCloser, 29 logger log.Logger) { 30 var lastStat syscall.Stat_t 31 lastFd := -1 32 for ; !stopped; time.Sleep(time.Second) { 33 var stat syscall.Stat_t 34 if err := syscall.Stat(pathname, &stat); err != nil { 35 if logger != nil { 36 logger.Printf("Error stating file: %s: %s\n", pathname, err) 37 } 38 continue 39 } 40 if stat.Ino != lastStat.Ino { 41 if file, err := os.Open(pathname); err != nil { 42 if logger != nil { 43 logger.Printf("Error opening file: %s: %s\n", pathname, err) 44 } 45 continue 46 } else { 47 // By holding onto the file, we guarantee that the inode number 48 // for the file we've opened cannot be reused until we've seen 49 // a new inode. 50 if lastFd >= 0 { 51 syscall.Close(lastFd) 52 } 53 lastFd, _ = syscall.Dup(int(file.Fd())) 54 channel <- file // Must happen after FD is duplicated. 55 lastStat = stat 56 } 57 } 58 } 59 if lastFd >= 0 { 60 syscall.Close(lastFd) 61 } 62 close(channel) 63 }