IBR-DTNSuite
0.8
|
00001 /* 00002 * FileMonitor.cpp 00003 * 00004 * Created on: 10.04.2012 00005 * Author: morgenro 00006 */ 00007 00008 #include "config.h" 00009 #include "net/FileMonitor.h" 00010 #include "core/BundleCore.h" 00011 #include <ibrcommon/Logger.h> 00012 #include <ibrcommon/data/ConfigFile.h> 00013 00014 #ifdef HAVE_SYS_INOTIFY_H 00015 #include <sys/inotify.h> 00016 #include <unistd.h> 00017 #endif 00018 00019 namespace dtn 00020 { 00021 namespace net 00022 { 00023 FileMonitor::FileMonitor() 00024 : _inotify_sock(0), _running(true) 00025 { 00026 #ifdef HAVE_SYS_INOTIFY_H 00027 _inotify_sock = inotify_init(); 00028 #endif 00029 } 00030 00031 FileMonitor::~FileMonitor() 00032 { 00033 join(); 00034 } 00035 00036 void FileMonitor::watch(const ibrcommon::File &watch) 00037 { 00038 IBRCOMMON_LOGGER_DEBUG(5) << "watch on: " << watch.getPath() << IBRCOMMON_LOGGER_ENDL; 00039 00040 if (!watch.isDirectory()) 00041 throw ibrcommon::Exception("can not watch files, please specify a directory"); 00042 00043 #ifdef HAVE_SYS_INOTIFY_H 00044 int wd = inotify_add_watch(_inotify_sock, watch.getPath().c_str(), IN_CREATE | IN_DELETE); 00045 _watch_map[wd] = watch; 00046 #endif 00047 } 00048 00049 void FileMonitor::componentUp() 00050 { 00051 #ifdef HAVE_SYS_INOTIFY_H 00052 _socket.add(_inotify_sock); 00053 #endif 00054 } 00055 00056 void FileMonitor::componentRun() 00057 { 00058 #ifdef HAVE_SYS_INOTIFY_H 00059 while (_running) 00060 { 00061 std::list<int> fds; 00062 00063 // scan for mounts 00064 scan(); 00065 00066 try { 00067 // select on all bound sockets 00068 _socket.select(fds); 00069 00070 unsigned char buf[1024]; 00071 00072 // receive from all sockets 00073 for (std::list<int>::const_iterator iter = fds.begin(); iter != fds.end(); iter++) 00074 { 00075 int fd = (*iter); 00076 ::read(fd, &buf, 1024); 00077 } 00078 00079 ::sleep(2); 00080 } catch (const ibrcommon::vsocket_timeout&) { }; 00081 } 00082 #endif 00083 } 00084 00085 void FileMonitor::componentDown() 00086 { 00087 #ifdef HAVE_SYS_INOTIFY_H 00088 for (watch_map::iterator iter = _watch_map.begin(); iter != _watch_map.end(); iter++) 00089 { 00090 const int wd = (*iter).first; 00091 inotify_rm_watch(_inotify_sock, wd); 00092 } 00093 #endif 00094 _watch_map.clear(); 00095 } 00096 00097 void FileMonitor::__cancellation() 00098 { 00099 #ifdef HAVE_SYS_INOTIFY_H 00100 _socket.close(); 00101 #endif 00102 } 00103 00104 void FileMonitor::scan() 00105 { 00106 IBRCOMMON_LOGGER_DEBUG(5) << "scan for file changes" << IBRCOMMON_LOGGER_ENDL; 00107 00108 std::set<ibrcommon::File> watch_set; 00109 00110 for (watch_map::iterator iter = _watch_map.begin(); iter != _watch_map.end(); iter++) 00111 { 00112 const ibrcommon::File &path = (*iter).second; 00113 std::list<ibrcommon::File> files; 00114 00115 if (path.getFiles(files) == 0) 00116 { 00117 for (std::list<ibrcommon::File>::iterator iter = files.begin(); iter != files.end(); iter++) 00118 { 00119 watch_set.insert(*iter); 00120 } 00121 } 00122 else 00123 { 00124 IBRCOMMON_LOGGER(error) << "scan of " << path.getPath() << " failed" << IBRCOMMON_LOGGER_ENDL; 00125 } 00126 } 00127 00128 // check for new directories 00129 for (std::set<ibrcommon::File>::iterator iter = watch_set.begin(); iter != watch_set.end(); iter++) 00130 { 00131 const ibrcommon::File &path = (*iter); 00132 if (path.isDirectory() && !path.isSystem()) 00133 { 00134 if (!isActive(path)) { 00135 adopt(path); 00136 } 00137 } 00138 } 00139 00140 // look for gone directories 00141 for (std::map<ibrcommon::File, dtn::core::Node>::iterator iter = _active_paths.begin(); iter != _active_paths.end();) 00142 { 00143 const ibrcommon::File &path = (*iter).first; 00144 const dtn::core::Node &node = (*iter).second; 00145 00146 if (watch_set.find(path) == watch_set.end()) 00147 { 00148 dtn::core::BundleCore::getInstance().removeConnection(node); 00149 IBRCOMMON_LOGGER_DEBUG(5) << "Node on drive gone: " << node.getEID().getString() << IBRCOMMON_LOGGER_ENDL; 00150 _active_paths.erase(iter++); 00151 } 00152 else 00153 { 00154 iter++; 00155 } 00156 } 00157 } 00158 00159 void FileMonitor::adopt(const ibrcommon::File &path) 00160 { 00161 // look for ".dtndrive" file 00162 const ibrcommon::File drivefile = path.get(".dtndrive"); 00163 if (drivefile.exists()) 00164 { 00165 ibrcommon::ConfigFile cf(drivefile.getPath()); 00166 00167 try { 00168 const dtn::data::EID eid( cf.read<std::string>("EID") ); 00169 00170 dtn::core::Node n(eid); 00171 const std::string uri = "file://" + path.getPath() + "/" + cf.read<std::string>("PATH"); 00172 00173 n.add(dtn::core::Node::URI(dtn::core::Node::NODE_STATIC, dtn::core::Node::CONN_FILE, uri, 0, 10)); 00174 dtn::core::BundleCore::getInstance().addConnection(n); 00175 00176 _active_paths[path] = n; 00177 00178 IBRCOMMON_LOGGER_DEBUG(5) << "Node on drive found: " << n.getEID().getString() << IBRCOMMON_LOGGER_ENDL; 00179 00180 } catch (const ibrcommon::ConfigFile::key_not_found&) {}; 00181 } 00182 } 00183 00184 bool FileMonitor::isActive(const ibrcommon::File &path) const 00185 { 00186 return (_active_paths.find(path) != _active_paths.end()); 00187 } 00188 00189 const std::string FileMonitor::getName() const 00190 { 00191 return "FileMonitor"; 00192 } 00193 } 00194 } /* namespace ibrcommon */