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  }