IBR-DTNSuite  0.10
FileMonitor.cpp
Go to the documentation of this file.
1 /*
2  * FileMonitor.cpp
3  *
4  * Copyright (C) 2011 IBR, TU Braunschweig
5  *
6  * Written-by: Johannes Morgenroth <morgenroth@ibr.cs.tu-bs.de>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21 
22 #include "config.h"
23 #include "net/FileMonitor.h"
24 #include "core/BundleCore.h"
25 #include <ibrcommon/Logger.h>
27 
28 #ifdef HAVE_SYS_INOTIFY_H
29 #include <sys/inotify.h>
30 #include <unistd.h>
31 #endif
32 
33 namespace dtn
34 {
35  namespace net
36  {
38  {
39  }
40 
42  {
43  }
44 
45  void inotifysocket::up() throw (ibrcommon::socket_exception)
46  {
47  if (_state != SOCKET_DOWN)
48  throw ibrcommon::socket_exception("socket is already up");
49 
50 #ifdef HAVE_SYS_INOTIFY_H
51  // initialize fd
52  _fd = inotify_init();
53 #endif
54 
55  _state = SOCKET_UP;
56  }
57 
58  void inotifysocket::down() throw (ibrcommon::socket_exception)
59  {
60  if (_state != SOCKET_UP)
61  throw ibrcommon::socket_exception("socket is not up");
62 
63 #ifdef HAVE_SYS_INOTIFY_H
64  for (watch_map::iterator iter = _watch_map.begin(); iter != _watch_map.end(); ++iter)
65  {
66  const int wd = (*iter).first;
67  inotify_rm_watch(this->fd(), wd);
68  }
69  _watch_map.clear();
70 
71  this->close();
72 #endif
73 
75  }
76 
78  {
79 #ifdef HAVE_SYS_INOTIFY_H
80  int wd = inotify_add_watch(this->fd(), path.getPath().c_str(), opts);
81  _watch_map[wd] = path;
82 #endif
83  }
84 
85  ssize_t inotifysocket::read(char *data, size_t len) throw (ibrcommon::socket_exception)
86  {
87 #ifdef HAVE_SYS_INOTIFY_H
88  return ::read(this->fd(), data, len);
89 #else
90  return 0;
91 #endif
92  }
93 
95  : _running(true)
96  {
97  }
98 
100  {
101  join();
102  }
103 
105  {
106  IBRCOMMON_LOGGER_DEBUG_TAG("FileMonitor", 5) << "watch on: " << watch.getPath() << IBRCOMMON_LOGGER_ENDL;
107 
108  if (!watch.isDirectory())
109  throw ibrcommon::Exception("can not watch files, please specify a directory");
110 
111  ibrcommon::socketset socks = _socket.getAll();
112  if (socks.size() == 0) return;
113  inotifysocket &sock = dynamic_cast<inotifysocket&>(**socks.begin());
114 
115 #ifdef HAVE_SYS_INOTIFY_H
116  sock.watch(watch, IN_CREATE | IN_DELETE);
117 #endif
118  _watchset.insert(watch);
119  }
120 
121  void FileMonitor::componentUp() throw ()
122  {
123  // routine checked for throw() on 15.02.2013
124  try {
125  _socket.up();
126  } catch (const ibrcommon::socket_exception &ex) {
127  IBRCOMMON_LOGGER_TAG("FileMonitor", error) << ex.what() << IBRCOMMON_LOGGER_ENDL;
128  }
129  }
130 
132  {
133 #ifdef HAVE_SYS_INOTIFY_H
134  while (_running)
135  {
137 
138  // scan for mounts
139  scan();
140 
141  try {
142  char buf[1024];
143 
144  // select on all bound sockets
145  _socket.select(&fds, NULL, NULL, NULL);
146 
147  // receive from all sockets
148  for (ibrcommon::socketset::iterator iter = fds.begin(); iter != fds.end(); ++iter)
149  {
150  inotifysocket &sock = dynamic_cast<inotifysocket&>(**iter);
151  sock.read((char*)&buf, 1024);
152  }
153 
154  ::sleep(2);
155  } catch (const ibrcommon::vsocket_interrupt&) {
156  return;
157  } catch (const ibrcommon::vsocket_timeout&) { };
158  }
159 #endif
160  }
161 
163  {
164  _socket.down();
165  }
166 
168  {
169  _socket.down();
170  }
171 
172  void FileMonitor::scan()
173  {
174  IBRCOMMON_LOGGER_DEBUG_TAG("FileMonitor", 5) << "scan for file changes" << IBRCOMMON_LOGGER_ENDL;
175 
176  std::set<ibrcommon::File> watch_set;
177 
178  for (watch_set::iterator iter = _watchset.begin(); iter != _watchset.end(); ++iter)
179  {
180  const ibrcommon::File &path = (*iter);
181  std::list<ibrcommon::File> files;
182 
183  if (path.getFiles(files) == 0)
184  {
185  for (std::list<ibrcommon::File>::iterator iter = files.begin(); iter != files.end(); ++iter)
186  {
187  watch_set.insert(*iter);
188  }
189  }
190  else
191  {
192  IBRCOMMON_LOGGER_TAG("FileMonitor", error) << "scan of " << path.getPath() << " failed" << IBRCOMMON_LOGGER_ENDL;
193  }
194  }
195 
196  // check for new directories
197  for (std::set<ibrcommon::File>::iterator iter = watch_set.begin(); iter != watch_set.end(); ++iter)
198  {
199  const ibrcommon::File &path = (*iter);
200  if (path.isDirectory() && !path.isSystem())
201  {
202  if (!isActive(path)) {
203  adopt(path);
204  }
205  }
206  }
207 
208  // look for gone directories
209  for (std::map<ibrcommon::File, dtn::core::Node>::iterator iter = _active_paths.begin(); iter != _active_paths.end();)
210  {
211  const ibrcommon::File &path = (*iter).first;
212  const dtn::core::Node &node = (*iter).second;
213 
214  if (watch_set.find(path) == watch_set.end())
215  {
217  IBRCOMMON_LOGGER_DEBUG_TAG("FileMonitor", 5) << "Node on drive gone: " << node.getEID().getString() << IBRCOMMON_LOGGER_ENDL;
218  _active_paths.erase(iter++);
219  }
220  else
221  {
222  ++iter;
223  }
224  }
225  }
226 
227  void FileMonitor::adopt(const ibrcommon::File &path)
228  {
229  // look for ".dtndrive" file
230  const ibrcommon::File drivefile = path.get(".dtndrive");
231  if (drivefile.exists())
232  {
233  ibrcommon::ConfigFile cf(drivefile.getPath());
234 
235  try {
236  const dtn::data::EID eid( cf.read<std::string>("EID") );
237 
238  dtn::core::Node n(eid);
239  const std::string uri = "file://" + path.getPath() + "/" + cf.read<std::string>("PATH");
240 
243 
244  _active_paths[path] = n;
245 
246  IBRCOMMON_LOGGER_DEBUG_TAG("FileMonitor", 5) << "Node on drive found: " << n.getEID().getString() << IBRCOMMON_LOGGER_ENDL;
247 
248  } catch (const ibrcommon::ConfigFile::key_not_found&) {};
249  }
250  }
251 
252  bool FileMonitor::isActive(const ibrcommon::File &path) const
253  {
254  return (_active_paths.find(path) != _active_paths.end());
255  }
256 
257  const std::string FileMonitor::getName() const
258  {
259  return "FileMonitor";
260  }
261  }
262 } /* namespace ibrcommon */