1c540156cSNicolas Bonnefon #include "inotifywatchtowerdriver.h" 2c540156cSNicolas Bonnefon 3*b278d183SNicolas Bonnefon #include <sys/inotify.h> 4*b278d183SNicolas Bonnefon #include <poll.h> 5*b278d183SNicolas Bonnefon #include <unistd.h> 6*b278d183SNicolas Bonnefon 7*b278d183SNicolas Bonnefon #include "log.h" 8*b278d183SNicolas Bonnefon 9*b278d183SNicolas Bonnefon #include "watchtowerlist.h" 10*b278d183SNicolas Bonnefon 11*b278d183SNicolas Bonnefon INotifyWatchTowerDriver::INotifyWatchTowerDriver() : inotify_fd_( inotify_init() ) 12c540156cSNicolas Bonnefon { 13c540156cSNicolas Bonnefon } 14c540156cSNicolas Bonnefon 15*b278d183SNicolas Bonnefon INotifyWatchTowerDriver::FileId INotifyWatchTowerDriver::addFile( 16*b278d183SNicolas Bonnefon const std::string& file_name ) 17c540156cSNicolas Bonnefon { 18c540156cSNicolas Bonnefon // Add a watch for the inode 19*b278d183SNicolas Bonnefon int wd = inotify_add_watch( inotify_fd_, file_name.c_str(), 20c540156cSNicolas Bonnefon IN_DELETE_SELF | IN_MODIFY | IN_MOVE_SELF ); 21c540156cSNicolas Bonnefon 22c540156cSNicolas Bonnefon LOG(logDEBUG) << "INotifyWatchTower::addFile new inotify wd " << wd; 23*b278d183SNicolas Bonnefon 24*b278d183SNicolas Bonnefon return { wd }; 25c540156cSNicolas Bonnefon } 26c540156cSNicolas Bonnefon 27*b278d183SNicolas Bonnefon INotifyWatchTowerDriver::SymlinkId INotifyWatchTowerDriver::addSymlink( 28*b278d183SNicolas Bonnefon const std::string& file_name ) 29c540156cSNicolas Bonnefon { 30*b278d183SNicolas Bonnefon int symlink_wd = inotify_add_watch( inotify_fd_, file_name.c_str(), 31c540156cSNicolas Bonnefon IN_DONT_FOLLOW | IN_DELETE_SELF | IN_MODIFY | IN_MOVE_SELF ); 32c540156cSNicolas Bonnefon LOG(logDEBUG) << "INotifyWatchTower::addFile new inotify symlink_wd " << symlink_wd; 33c540156cSNicolas Bonnefon // (not sure a symlink can be modified but you never know) 34*b278d183SNicolas Bonnefon 35*b278d183SNicolas Bonnefon return { symlink_wd }; 36c540156cSNicolas Bonnefon } 37c540156cSNicolas Bonnefon 38*b278d183SNicolas Bonnefon INotifyWatchTowerDriver::DirId INotifyWatchTowerDriver::addDir( 39*b278d183SNicolas Bonnefon const std::string& file_name ) 40*b278d183SNicolas Bonnefon { 41*b278d183SNicolas Bonnefon int dir_wd = inotify_add_watch( inotify_fd_, file_name.c_str(), 42*b278d183SNicolas Bonnefon IN_CREATE | IN_MOVE | IN_ONLYDIR ); 43*b278d183SNicolas Bonnefon LOG(logDEBUG) << "INotifyWatchTower::addFile dir " << file_name 44*b278d183SNicolas Bonnefon << " watched wd " << dir_wd; 45*b278d183SNicolas Bonnefon 46*b278d183SNicolas Bonnefon return { dir_wd }; 47*b278d183SNicolas Bonnefon } 48*b278d183SNicolas Bonnefon 49*b278d183SNicolas Bonnefon void INotifyWatchTowerDriver::removeFile( 50*b278d183SNicolas Bonnefon const INotifyWatchTowerDriver::FileId& file_id ) 51c540156cSNicolas Bonnefon { 52c540156cSNicolas Bonnefon /* 53c540156cSNicolas Bonnefon LOG(logDEBUG) << "INotifyWatchTower::removeNotification removing inotify wd " 54c540156cSNicolas Bonnefon << file->file_wd_ << " symlink_wd " << file->symlink_wd_; 55c540156cSNicolas Bonnefon */ 56*b278d183SNicolas Bonnefon if ( file_id.wd_ >= 0 ) 57*b278d183SNicolas Bonnefon inotify_rm_watch( inotify_fd_, file_id.wd_ ); 58c540156cSNicolas Bonnefon } 59c540156cSNicolas Bonnefon 60*b278d183SNicolas Bonnefon void INotifyWatchTowerDriver::removeSymlink( const SymlinkId& symlink_id ) 61c540156cSNicolas Bonnefon { 62*b278d183SNicolas Bonnefon if ( symlink_id.wd_ >= 0 ) 63*b278d183SNicolas Bonnefon inotify_rm_watch( inotify_fd_, symlink_id.wd_ ); 64c540156cSNicolas Bonnefon } 65c540156cSNicolas Bonnefon 66*b278d183SNicolas Bonnefon static const size_t INOTIFY_BUFFER_SIZE = 4096; 67*b278d183SNicolas Bonnefon 68*b278d183SNicolas Bonnefon std::vector<ObservedFile*> INotifyWatchTowerDriver::waitAndProcessEvents( 69*b278d183SNicolas Bonnefon ObservedFileList* list, 70*b278d183SNicolas Bonnefon std::mutex* list_mutex ) 71c540156cSNicolas Bonnefon { 72*b278d183SNicolas Bonnefon std::vector<ObservedFile*> files_to_notify; 73*b278d183SNicolas Bonnefon struct pollfd fds[1]; 74*b278d183SNicolas Bonnefon 75*b278d183SNicolas Bonnefon fds[0].fd = inotify_fd_; 76*b278d183SNicolas Bonnefon fds[0].events = POLLIN; 77c540156cSNicolas Bonnefon fds[0].revents = 0; 78*b278d183SNicolas Bonnefon 79c540156cSNicolas Bonnefon int poll_ret = poll( fds, 1, 0 ); 80c540156cSNicolas Bonnefon 81c540156cSNicolas Bonnefon if ( ( poll_ret > 0 ) && ( fds[0].revents & POLLIN ) ) 82c540156cSNicolas Bonnefon { 83c540156cSNicolas Bonnefon LOG(logDEBUG4) << "Pollin for inotify"; 84c540156cSNicolas Bonnefon char buffer[ INOTIFY_BUFFER_SIZE ] 85c540156cSNicolas Bonnefon __attribute__ ((aligned(__alignof__(struct inotify_event)))); 86c540156cSNicolas Bonnefon 87*b278d183SNicolas Bonnefon ssize_t nb = read( inotify_fd_, buffer, sizeof( buffer ) ); 88c540156cSNicolas Bonnefon if ( nb > 0 ) 89c540156cSNicolas Bonnefon { 90c540156cSNicolas Bonnefon size_t offset = 0; 91c540156cSNicolas Bonnefon while ( offset < nb ) { 92c540156cSNicolas Bonnefon const inotify_event* event = 93c540156cSNicolas Bonnefon reinterpret_cast<const inotify_event*>( buffer + offset ); 94c540156cSNicolas Bonnefon 95*b278d183SNicolas Bonnefon offset += processINotifyEvent( event, list, list_mutex, &files_to_notify ); 96c540156cSNicolas Bonnefon } 97c540156cSNicolas Bonnefon } 98c540156cSNicolas Bonnefon else 99c540156cSNicolas Bonnefon { 100c540156cSNicolas Bonnefon LOG(logWARNING) << "Error reading from inotify " << errno; 101c540156cSNicolas Bonnefon } 102c540156cSNicolas Bonnefon } 103c540156cSNicolas Bonnefon 104*b278d183SNicolas Bonnefon return files_to_notify; 105*b278d183SNicolas Bonnefon } 106*b278d183SNicolas Bonnefon 107c540156cSNicolas Bonnefon // Treats the passed event and returns the number of bytes used 108*b278d183SNicolas Bonnefon size_t INotifyWatchTowerDriver::processINotifyEvent( 109*b278d183SNicolas Bonnefon const struct inotify_event* event, 110*b278d183SNicolas Bonnefon ObservedFileList* list, 111*b278d183SNicolas Bonnefon std::mutex* list_mutex, 112*b278d183SNicolas Bonnefon std::vector<ObservedFile*>* files_to_notify ) 113c540156cSNicolas Bonnefon { 114c540156cSNicolas Bonnefon LOG(logDEBUG) << "Event received: " << std::hex << event->mask; 115c540156cSNicolas Bonnefon 116*b278d183SNicolas Bonnefon std::unique_lock<std::mutex> lock( *list_mutex ); 117c540156cSNicolas Bonnefon 118c540156cSNicolas Bonnefon ObservedFile* file = nullptr; 119c540156cSNicolas Bonnefon 120c540156cSNicolas Bonnefon if ( event->mask & ( IN_MODIFY | IN_DELETE_SELF | IN_MOVE_SELF ) ) 121c540156cSNicolas Bonnefon { 122c540156cSNicolas Bonnefon LOG(logDEBUG) << "IN_MODIFY | IN_DELETE_SELF | IN_MOVE_SELF for wd " << event->wd; 123c540156cSNicolas Bonnefon 124c540156cSNicolas Bonnefon // Retrieve the file 125*b278d183SNicolas Bonnefon file = list->searchByFileOrSymlinkWd( 126*b278d183SNicolas Bonnefon { event->wd }, { event->wd } ); 127c540156cSNicolas Bonnefon } 128c540156cSNicolas Bonnefon else if ( event->mask & ( IN_CREATE | IN_MOVED_TO | IN_MOVED_FROM ) ) 129c540156cSNicolas Bonnefon { 130c540156cSNicolas Bonnefon LOG(logDEBUG) << "IN_CREATE | IN_MOVED_TO | IN_MOVED_FROM for wd " << event->wd 131c540156cSNicolas Bonnefon << " name: " << event->name; 132c540156cSNicolas Bonnefon 133c540156cSNicolas Bonnefon // Retrieve the file 134*b278d183SNicolas Bonnefon file = list->searchByDirWdAndName( { event->wd }, event->name ); 135c540156cSNicolas Bonnefon 136c540156cSNicolas Bonnefon if ( file ) 137c540156cSNicolas Bonnefon { 138c540156cSNicolas Bonnefon LOG(logDEBUG) << "Dir change for watched file " << event->name; 139c540156cSNicolas Bonnefon } 140c540156cSNicolas Bonnefon } 141c540156cSNicolas Bonnefon else 142c540156cSNicolas Bonnefon { 143c540156cSNicolas Bonnefon LOG(logDEBUG) << "Unexpected event: " << event->mask << " wd " << event->wd; 144c540156cSNicolas Bonnefon } 145c540156cSNicolas Bonnefon 146c540156cSNicolas Bonnefon // Call all our observers 147c540156cSNicolas Bonnefon if ( file ) 148c540156cSNicolas Bonnefon { 149*b278d183SNicolas Bonnefon files_to_notify->push_back( file ); 150c540156cSNicolas Bonnefon } 151c540156cSNicolas Bonnefon 152c540156cSNicolas Bonnefon return sizeof( struct inotify_event ) + event->len; 153c540156cSNicolas Bonnefon } 154