示例#1
0
bool INotifyEventPublisher::monitorSubscription(
    INotifySubscriptionContextRef& sc, bool add_watch) {
    sc->discovered_ = sc->path;
    if (sc->path.find("**") != std::string::npos) {
        sc->recursive = true;
        sc->discovered_ = sc->path.substr(0, sc->path.find("**"));
        sc->path = sc->discovered_;
    }

    if (sc->path.find('*') != std::string::npos) {
        // If the wildcard exists within the file (leaf), remove and monitor the
        // directory instead. Apply a fnmatch on fired events to filter leafs.
        auto fullpath = fs::path(sc->path);
        if (fullpath.filename().string().find('*') != std::string::npos) {
            sc->discovered_ = fullpath.parent_path().string() + '/';
        }

        if (sc->discovered_.find('*') != std::string::npos) {
            // If a wildcard exists within the tree (stem), resolve at configure
            // time and monitor each path.
            std::vector<std::string> paths;
            resolveFilePattern(sc->discovered_, paths);
            for (const auto& _path : paths) {
                addMonitor(_path, sc->mask, sc->recursive, add_watch);
            }
            sc->recursive_match = sc->recursive;
            return true;
        }
    }
    if (isDirectory(sc->discovered_) && sc->discovered_.back() != '/') {
        sc->path += '/';
        sc->discovered_ += '/';
    }
    return addMonitor(sc->discovered_, sc->mask, sc->recursive, add_watch);
}
示例#2
0
bool INotifyEventPublisher::addMonitor(const std::string& path,
                                       bool recursive) {
  if (!isPathMonitored(path)) {
    int watch = ::inotify_add_watch(getHandle(), path.c_str(), IN_ALL_EVENTS);
    if (watch == -1) {
      LOG(ERROR) << "Could not add inotfy watch on: " << path;
      return false;
    }

    // Keep a list of the watch descriptors
    descriptors_.push_back(watch);
    // Keep a map of the path -> watch descriptor
    path_descriptors_[path] = watch;
    // Keep a map of the opposite (descriptor -> path)
    descriptor_paths_[watch] = path;
  }

  if (recursive && isDirectory(path).ok()) {
    std::vector<std::string> children;
    // Get a list of children of this directory (requesed recursive watches).
    listDirectoriesInDirectory(path, children);

    for (const auto& child : children) {
      addMonitor(child, recursive);
    }
  }

  return true;
}
示例#3
0
bool INotifyEventPublisher::addMonitor(const std::string& path,
                                       uint32_t mask,
                                       bool recursive,
                                       bool add_watch) {
    if (!isPathMonitored(path)) {
        int watch = ::inotify_add_watch(
                        getHandle(), path.c_str(), ((mask == 0) ? kFileDefaultMasks : mask));
        if (add_watch && watch == -1) {
            LOG(WARNING) << "Could not add inotify watch on: " << path;
            return false;
        }

        // Keep a list of the watch descriptors
        descriptors_.push_back(watch);
        // Keep a map of the path -> watch descriptor
        path_descriptors_[path] = watch;
        // Keep a map of the opposite (descriptor -> path)
        descriptor_paths_[watch] = path;
    }

    if (recursive && isDirectory(path).ok()) {
        std::vector<std::string> children;
        // Get a list of children of this directory (requested recursive watches).
        listDirectoriesInDirectory(path, children, true);

        boost::system::error_code ec;
        for (const auto& child : children) {
            auto canonicalized = fs::canonical(child, ec).string() + '/';
            addMonitor(canonicalized, mask, false);
        }
    }

    return true;
}
示例#4
0
Status INotifyEventPublisher::run() {
  // Get a while wrapper for free.
  char buffer[BUFFER_SIZE];
  fd_set set;

  FD_ZERO(&set);
  FD_SET(getHandle(), &set);

  struct timeval timeout = {3, 3000};
  int selector = ::select(getHandle() + 1, &set, nullptr, nullptr, &timeout);
  if (selector == -1) {
    LOG(ERROR) << "Could not read inotify handle";
    return Status(1, "INotify handle failed");
  }

  if (selector == 0) {
    // Read timeout.
    return Status(0, "Continue");
  }
  ssize_t record_num = ::read(getHandle(), buffer, BUFFER_SIZE);
  if (record_num == 0 || record_num == -1) {
    return Status(1, "INotify read failed");
  }

  for (char* p = buffer; p < buffer + record_num;) {
    // Cast the inotify struct, make shared pointer, and append to contexts.
    auto event = reinterpret_cast<struct inotify_event*>(p);
    if (event->mask & IN_Q_OVERFLOW) {
      // The inotify queue was overflown (remove all paths).
      Status stat = restartMonitoring();
      if(!stat.ok()){
        return stat;
      }
    }

    if (event->mask & IN_IGNORED) {
      // This inotify watch was removed.
      removeMonitor(event->wd, false);
    } else if (event->mask & IN_MOVE_SELF) {
      // This inotify path was moved, but is still watched.
      removeMonitor(event->wd, true);
    } else if (event->mask & IN_DELETE_SELF) {
      // A file was moved to replace the watched path.
      removeMonitor(event->wd, false);
    } else {
      auto ec = createEventContextFrom(event);
      if(event->mask & IN_CREATE && isDirectory(ec->path).ok()){
        addMonitor(ec->path, 1);
      }
      fire(ec);
    }
    // Continue to iterate
    p += (sizeof(struct inotify_event)) + event->len;
  }

  osquery::publisherSleep(kINotifyMLatency);
  return Status(0, "Continue");
}
示例#5
0
void INotifyEventPublisher::configure() {
  for (const auto& sub : subscriptions_) {
    // Anytime a configure is called, try to monitor all subscriptions.
    // Configure is called as a response to removing/adding subscriptions.
    // This means recalculating all monitored paths.
    auto sc = getSubscriptionContext(sub->context);
    addMonitor(sc->path, sc->recursive);
  }
}
示例#6
0
void INotifyEventPublisher::configure() {
  for (auto& sub : subscriptions_) {
    // Anytime a configure is called, try to monitor all subscriptions.
    // Configure is called as a response to removing/adding subscriptions.
    // This means recalculating all monitored paths.
    auto sc = getSubscriptionContext(sub->context);
    if (sc->discovered_.size() > 0) {
      continue;
    }

    sc->discovered_ = sc->path;
    if (sc->path.find("**") != std::string::npos) {
      sc->recursive = true;
      sc->discovered_ = sc->path.substr(0, sc->path.find("**"));
      sc->path = sc->discovered_;
    }

    if (sc->path.find('*') != std::string::npos) {
      // If the wildcard exists within the file (leaf), remove and monitor the
      // directory instead. Apply a fnmatch on fired events to filter leafs.
      auto fullpath = fs::path(sc->path);
      if (fullpath.filename().string().find('*') != std::string::npos) {
        sc->discovered_ = fullpath.parent_path().string();
      }

      if (sc->discovered_.find('*') != std::string::npos) {
        // If a wildcard exists within the tree (stem), resolve at configure
        // time and monitor each path.
        std::vector<std::string> paths;
        resolveFilePattern(sc->discovered_, paths);
        for (const auto& _path : paths) {
          addMonitor(_path, sc->recursive);
        }
        sc->recursive_match = sc->recursive;
        continue;
      }
    }
    addMonitor(sc->discovered_, sc->recursive);
  }
}
示例#7
0
TEST_F(INotifyTests, test_inotify_match_subscription) {
  event_pub_ = std::make_shared<INotifyEventPublisher>(true);
  addMonitor("/etc", IN_ALL_EVENTS, false, false);
  EXPECT_EQ(event_pub_->path_descriptors_.count("/etc"), 1U);
  // This will fail because there is no trailing "/" at the end.
  // The configure component should take care of these paths.
  EXPECT_FALSE(event_pub_->isPathMonitored("/etc/passwd"));
  event_pub_->path_descriptors_.clear();

  // Calling addMonitor the correct way.
  addMonitor("/etc/", IN_ALL_EVENTS, false, false);
  EXPECT_TRUE(event_pub_->isPathMonitored("/etc/passwd"));
  event_pub_->path_descriptors_.clear();

  // Test the matching capability.
  {
    auto sc = event_pub_->createSubscriptionContext();
    sc->path = "/etc";
    event_pub_->monitorSubscription(sc, false);
    EXPECT_EQ(sc->path, "/etc/");
    EXPECT_TRUE(event_pub_->isPathMonitored("/etc/"));
    EXPECT_TRUE(event_pub_->isPathMonitored("/etc/passwd"));
  }

  std::vector<std::string> valid_dirs = {"/etc", "/etc/", "/etc/*"};
  for (const auto& dir : valid_dirs) {
    event_pub_->path_descriptors_.clear();
    auto sc = event_pub_->createSubscriptionContext();
    sc->path = dir;
    event_pub_->monitorSubscription(sc, false);
    auto ec = event_pub_->createEventContext();
    ec->path = "/etc/";
    EXPECT_TRUE(event_pub_->shouldFire(sc, ec));
    ec->path = "/etc/passwd";
    EXPECT_TRUE(event_pub_->shouldFire(sc, ec));
  }
}