/** * Loaded tables are registered for processing events. * * \param[in] pIn inotify object * \param[in] pEd inotify event dispatcher * * \throw InotifyException thrown if base table directory cannot be read */ void load_tables(Inotify* pIn, EventDispatcher* pEd) throw (InotifyException) { DIR* d = opendir(INCRON_TABLE_BASE); if (d == NULL) throw InotifyException("cannot open table directory", errno); syslog(LOG_NOTICE, "loading user tables"); struct dirent* pDe = NULL; while ((pDe = readdir(d)) != NULL) { std::string un(pDe->d_name); if (pDe->d_type == DT_REG && un != "." && un != "..") { if (check_user(pDe->d_name)) { syslog(LOG_INFO, "loading table for user %s", pDe->d_name); UserTable* pUt = new UserTable(pIn, pEd, un); g_ut.insert(SUT_MAP::value_type(un, pUt)); pUt->Load(); } else { syslog(LOG_WARNING, "table for invalid user %s found (ignored)", pDe->d_name); } } } closedir(d); }
void EventDispatcher::ProcessMgmtEvents() { m_pIn->WaitForEvents(true); InotifyEvent e; while (m_pIn->GetEvent(e)) { if (e.GetWatch() == m_pSys) { if (e.IsType(IN_DELETE_SELF) || e.IsType(IN_UNMOUNT)) { syslog(LOG_CRIT, "base directory destroyed, exitting"); g_fFinish = true; } else if (!e.GetName().empty()) { SUT_MAP::iterator it = g_ut.find(IncronCfg::BuildPath(m_pSys->GetPath(), e.GetName())); if (it != g_ut.end()) { UserTable* pUt = (*it).second; if (e.IsType(IN_CLOSE_WRITE) || e.IsType(IN_MOVED_TO)) { syslog(LOG_INFO, "system table %s changed, reloading", e.GetName().c_str()); pUt->Dispose(); pUt->Load(); } else if (e.IsType(IN_MOVED_FROM) || e.IsType(IN_DELETE)) { syslog(LOG_INFO, "system table %s destroyed, removing", e.GetName().c_str()); delete pUt; g_ut.erase(it); } } else if (e.IsType(IN_CLOSE_WRITE) || e.IsType(IN_MOVED_TO)) { syslog(LOG_INFO, "system table %s created, loading", e.GetName().c_str()); UserTable* pUt = new UserTable(this, e.GetName(), true); g_ut.insert(SUT_MAP::value_type(IncronTab::GetSystemTablePath(e.GetName()), pUt)); pUt->Load(); } } } else if (e.GetWatch() == m_pUser) { if (e.IsType(IN_DELETE_SELF) || e.IsType(IN_UNMOUNT)) { syslog(LOG_CRIT, "base directory destroyed, exitting"); g_fFinish = true; } else if (!e.GetName().empty()) { SUT_MAP::iterator it = g_ut.find(IncronCfg::BuildPath(m_pUser->GetPath(), e.GetName())); if (it != g_ut.end()) { UserTable* pUt = (*it).second; if (e.IsType(IN_CLOSE_WRITE) || e.IsType(IN_MOVED_TO)) { syslog(LOG_INFO, "table for user %s changed, reloading", e.GetName().c_str()); pUt->Dispose(); pUt->Load(); } else if (e.IsType(IN_MOVED_FROM) || e.IsType(IN_DELETE)) { syslog(LOG_INFO, "table for user %s destroyed, removing", e.GetName().c_str()); delete pUt; g_ut.erase(it); } } else if (e.IsType(IN_CLOSE_WRITE) || e.IsType(IN_MOVED_TO)) { if (UserTable::CheckUser(e.GetName().c_str())) { syslog(LOG_INFO, "table for user %s created, loading", e.GetName().c_str()); UserTable* pUt = new UserTable(this, e.GetName(), false); g_ut.insert(SUT_MAP::value_type(IncronTab::GetUserTablePath(e.GetName()), pUt)); pUt->Load(); } } } } } }
/** * \param[in] argc argument count * \param[in] argv argument array * \return 0 on success, 1 on error * * \attention In daemon mode, it finishes immediately. */ int main(int argc, char** argv) { openlog(INCRON_DAEMON_NAME, INCRON_LOG_OPTS, INCRON_LOG_FACIL); syslog(LOG_NOTICE, "starting service (version %s, built on %s %s)", INCRON_VERSION, __DATE__, __TIME__); try { Inotify in; in.SetNonBlock(true); EventDispatcher ed(&in); try { load_tables(&in, &ed); } catch (InotifyException e) { int err = e.GetErrorNumber(); syslog(LOG_CRIT, "%s: (%i) %s", e.GetMessage().c_str(), err, strerror(err)); syslog(LOG_NOTICE, "stopping service"); closelog(); return 1; } signal(SIGTERM, on_signal); signal(SIGINT, on_signal); signal(SIGCHLD, on_signal); if (DAEMON) daemon(0, 0); uint32_t wm = IN_CLOSE_WRITE | IN_DELETE | IN_MOVE | IN_DELETE_SELF | IN_UNMOUNT; InotifyWatch watch(INCRON_TABLE_BASE, wm); in.Add(watch); syslog(LOG_NOTICE, "ready to process filesystem events"); InotifyEvent e; struct pollfd pfd; pfd.fd = in.GetDescriptor(); pfd.events = (short) POLLIN; pfd.revents = (short) 0; while (!g_fFinish) { int res = poll(&pfd, 1, -1); if (res > 0) { in.WaitForEvents(true); } else if (res < 0) { if (errno != EINTR) throw InotifyException("polling failed", errno, NULL); } UserTable::FinishDone(); while (in.GetEvent(e)) { if (e.GetWatch() == &watch) { if (e.IsType(IN_DELETE_SELF) || e.IsType(IN_UNMOUNT)) { syslog(LOG_CRIT, "base directory destroyed, exitting"); g_fFinish = true; } else if (!e.GetName().empty()) { SUT_MAP::iterator it = g_ut.find(e.GetName()); if (it != g_ut.end()) { UserTable* pUt = (*it).second; if (e.IsType(IN_CLOSE_WRITE) || e.IsType(IN_MOVED_TO)) { syslog(LOG_INFO, "table for user %s changed, reloading", e.GetName().c_str()); pUt->Dispose(); pUt->Load(); } else if (e.IsType(IN_MOVED_FROM) || e.IsType(IN_DELETE)) { syslog(LOG_INFO, "table for user %s destroyed, removing", e.GetName().c_str()); delete pUt; g_ut.erase(it); } } else if (e.IsType(IN_CLOSE_WRITE) || e.IsType(IN_MOVED_TO)) { if (check_user(e.GetName().c_str())) { syslog(LOG_INFO, "table for user %s created, loading", e.GetName().c_str()); UserTable* pUt = new UserTable(&in, &ed, e.GetName()); g_ut.insert(SUT_MAP::value_type(e.GetName(), pUt)); pUt->Load(); } } } } else { ed.DispatchEvent(e); } } } } catch (InotifyException e) { int err = e.GetErrorNumber(); syslog(LOG_CRIT, "*** unhandled exception occurred ***"); syslog(LOG_CRIT, " %s", e.GetMessage().c_str()); syslog(LOG_CRIT, " error: (%i) %s", err, strerror(err)); } syslog(LOG_NOTICE, "stopping service"); closelog(); return 0; }
/** * Loaded tables are registered for processing events. * * \param[in] pEd inotify event dispatcher * * \throw InotifyException thrown if base table directory cannot be read */ void load_tables(EventDispatcher* pEd) throw (InotifyException) { // WARNING - this function has not been optimized!!! std::string s; if (!IncronCfg::GetValue("system_table_dir", s)) throw InotifyException("configuration system is corrupted", EINVAL); DIR* d = opendir(s.c_str()); if (d != NULL) { syslog(LOG_NOTICE, "loading system tables"); struct dirent* pDe = NULL; while ((pDe = readdir(d)) != NULL) { std::string un(pDe->d_name); std::string path(IncronCfg::BuildPath(s, pDe->d_name)); bool ok = pDe->d_type == DT_REG; if (pDe->d_type == DT_UNKNOWN) { struct stat st; if (stat(path.c_str(), &st) == 0) ok = S_ISREG(st.st_mode); } if (ok) { syslog(LOG_INFO, "loading table %s", pDe->d_name); UserTable* pUt = new UserTable(pEd, un, true); g_ut.insert(SUT_MAP::value_type(path, pUt)); pUt->Load(); } } closedir(d); } else { syslog(LOG_WARNING, "cannot open system table directory (ignoring)"); } if (!IncronCfg::GetValue("user_table_dir", s)) throw InotifyException("configuration system is corrupted", EINVAL); d = opendir(s.c_str()); if (d == NULL) throw InotifyException("cannot open user table directory", errno); syslog(LOG_NOTICE, "loading user tables"); struct dirent* pDe = NULL; while ((pDe = readdir(d)) != NULL) { std::string un(pDe->d_name); std::string path(IncronCfg::BuildPath(s, pDe->d_name)); bool ok = pDe->d_type == DT_REG; if (pDe->d_type == DT_UNKNOWN) { struct stat st; if (stat(path.c_str(), &st) == 0) ok = S_ISREG(st.st_mode); } if (ok) { if (UserTable::CheckUser(pDe->d_name)) { syslog(LOG_INFO, "loading table for user %s", pDe->d_name); UserTable* pUt = new UserTable(pEd, un, false); g_ut.insert(SUT_MAP::value_type(path, pUt)); pUt->Load(); } else { syslog(LOG_WARNING, "table for invalid user %s found (ignored)", pDe->d_name); } } } closedir(d); }