/incron/trunk/ict-main.cpp |
---|
29,10 → 29,10 |
#define INCRON_DEFAULT_EDITOR "vim" |
const char* argp_program_version = "incrontab 0.1.0"; |
const char* argp_program_version = "incrontab 0.3.0"; |
const char* argp_program_bug_address = "<bugs@aiken.cz>"; |
static char doc[] = "Table manipulator for incrond (inotify Cron daemon)"; |
static char doc[] = "Table manipulator for incrond (inotify cron daemon)"; |
static char args_doc[] = "FILE"; |
44,22 → 44,31 |
{ 0 } |
}; |
enum |
/// incrontab operations |
typedef enum |
{ |
OPER_NONE, |
OPER_LIST, |
OPER_REMOVE, |
OPER_EDIT |
}; |
OPER_NONE, /// nothing |
OPER_LIST, /// list table |
OPER_REMOVE, /// remove table |
OPER_EDIT /// edit table |
} InCronTab_Operation_t; |
/// incrontab arguments |
struct arguments |
{ |
char *user; |
int oper; |
char *file; |
char *user; /// user name |
int oper; /// operation code |
char *file; /// file to import |
}; |
static error_t parse_opt (int key, char *arg, struct argp_state *state) |
/// Parses the program options (arguments). |
/** |
* \param[in] key argument key (name) |
* \param[in] arg argument value |
* \param[out] state options setting |
* \return 0 on success, ARGP_ERR_UNKNOWN on unknown argument(s) |
*/ |
static error_t parse_opt(int key, char *arg, struct argp_state *state) |
{ |
struct arguments* arguments = (struct arguments*) state->input; |
90,9 → 99,16 |
return 0; |
} |
/// Program arguments |
static struct argp argp = { options, parse_opt, args_doc, doc }; |
/// Unlink a file with temporarily changed UID. |
/** |
* \param[in] file file to unlink |
* \param[in] uid UID for unlink processing |
* |
* \attention No error checking is done! |
*/ |
void unlink_suid(const char* file, uid_t uid) |
{ |
uid_t iu = geteuid(); |
101,6 → 117,12 |
seteuid(iu); |
} |
/// Copies a file to an user table. |
/** |
* \param[in] path path to file |
* \param[in] user user name |
* \return true = success, false = failure |
*/ |
bool copy_from_file(const char* path, const char* user) |
{ |
InCronTab tab; |
121,6 → 143,11 |
return true; |
} |
/// Removes an user table. |
/** |
* \param[in] user user name |
* \return true = success, false = failure |
*/ |
bool remove_table(const char* user) |
{ |
std::string tp(InCronTab::GetUserTablePath(user)); |
133,6 → 160,13 |
return true; |
} |
/// Lists an user table. |
/** |
* \param[in] user user name |
* \return true = success, false = failure |
* |
* \attention Listing is currently done through 'cat'. |
*/ |
bool list_table(const char* user) |
{ |
std::string tp(InCronTab::GetUserTablePath(user)); |
153,6 → 187,15 |
return system(cmd.c_str()) == 0; |
} |
/// Allows to edit an user table. |
/** |
* \param[in] user user name |
* \return true = success, false = failure |
* |
* \attention This function is very complex and may contain |
* various bugs including security ones. Please keep |
* it in mind.. |
*/ |
bool edit_table(const char* user) |
{ |
std::string tp(InCronTab::GetUserTablePath(user)); |
/incron/trunk/CHANGELOG |
---|
1,3 → 1,11 |
0.2.1 2006-10-14 |
* based on inotify-cxx 0.4.1 (it should also fix crashing as described in #0000085) |
* build failure (due to missing 'useradd -M') on some distributions has been fixed |
(#0000094) |
* tarball structure has been fixed (#0000089) |
* documentation slightly improved |
0.2.0 2006-10-04 |
* based on inotify-cxx 0.3.1 |
* better signal handling (no "dirty" wait() in a handler) |
/incron/trunk/inotify-cxx.cpp |
---|
81,6 → 81,16 |
else if (rName == "IN_ALL_EVENTS") |
return IN_ALL_EVENTS; |
#ifdef IN_DONT_FOLLOW |
else if (rName == "IN_DONT_FOLLOW") |
return IN_DONT_FOLLOW; |
#endif // IN_DONT_FOLLOW |
#ifdef IN_ONLYDIR |
else if (rName == "IN_ONLYDIR") |
return IN_ONLYDIR; |
#endif // IN_ONLYDIR |
return (uint32_t) 0; |
} |
169,6 → 179,20 |
DUMP_SEP; |
rStr.append("IN_ONESHOT"); |
} |
#ifdef IN_DONT_FOLLOW |
if (IsType(uValue, IN_DONT_FOLLOW)) { |
DUMP_SEP; |
rStr.append("IN_DONT_FOLLOW"); |
} |
#endif // IN_DONT_FOLLOW |
#ifdef IN_ONLYDIR |
if (IsType(uValue, IN_ONLYDIR)) { |
DUMP_SEP; |
rStr.append("IN_ONLYDIR"); |
} |
#endif // IN_ONLYDIR |
} |
void InotifyEvent::DumpTypes(std::string& rStr) const |
177,11 → 201,46 |
} |
void InotifyWatch::SetMask(uint32_t uMask) throw (InotifyException) |
{ |
if (m_wd != -1) { |
int wd = inotify_add_watch(m_pInotify->GetDescriptor(), m_path.c_str(), uMask); |
if (wd != m_wd) |
throw InotifyException(IN_EXC_MSG("changing mask failed"), wd == -1 ? errno : EINVAL, this); |
} |
m_uMask = uMask; |
} |
void InotifyWatch::SetEnabled(bool fEnabled) throw (InotifyException) |
{ |
if (fEnabled == m_fEnabled) |
return; |
if (m_pInotify != NULL) { |
if (fEnabled) { |
m_wd = inotify_add_watch(m_pInotify->GetDescriptor(), m_path.c_str(), m_uMask); |
if (m_wd == -1) |
throw InotifyException(IN_EXC_MSG("enabling watch failed"), errno, this); |
m_pInotify->m_watches.insert(IN_WATCH_MAP::value_type(m_wd, this)); |
} |
else { |
if (inotify_rm_watch(m_pInotify->GetDescriptor(), m_wd) != 0) |
throw InotifyException(IN_EXC_MSG("disabling watch failed"), errno, this); |
m_pInotify->m_watches.erase(m_wd); |
m_wd = -1; |
} |
} |
m_fEnabled = fEnabled; |
} |
Inotify::Inotify() throw (InotifyException) |
{ |
m_fd = inotify_init(); |
if (m_fd == -1) |
throw InotifyException(std::string(__PRETTY_FUNCTION__) + ": inotify init failed", errno, NULL); |
throw InotifyException(IN_EXC_MSG("inotify init failed"), errno, NULL); |
} |
Inotify::~Inotify() |
200,43 → 259,81 |
void Inotify::Add(InotifyWatch* pWatch) throw (InotifyException) |
{ |
// invalid descriptor - this case shouldn't occur - go away |
if (m_fd == -1) |
throw InotifyException(IN_EXC_MSG("invalid file descriptor"), EBUSY, this); |
// this path already watched - go away |
if (FindWatch(pWatch->GetPath()) != NULL) |
throw InotifyException(IN_EXC_MSG("path already watched"), EBUSY, this); |
// for enabled watch |
if (pWatch->IsEnabled()) { |
pWatch->m_wd = inotify_add_watch(m_fd, pWatch->GetPath().c_str(), pWatch->GetMask()); |
if (pWatch->m_wd == -1) |
throw InotifyException(IN_EXC_MSG("adding watch failed"), errno, this); |
m_watches.insert(IN_WATCH_MAP::value_type(pWatch->m_wd, pWatch)); |
// try to add watch to kernel |
int wd = inotify_add_watch(m_fd, pWatch->GetPath().c_str(), pWatch->GetMask()); |
// adding failed - go away |
if (wd == -1) |
throw InotifyException(IN_EXC_MSG("adding watch failed"), errno, this); |
// this path already watched (but defined another way) |
InotifyWatch* pW = FindWatch(wd); |
if (pW != NULL) { |
// try to recover old watch because it may be modified - then go away |
if (inotify_add_watch(m_fd, pW->GetPath().c_str(), pW->GetMask()) < 0) { |
throw InotifyException(IN_EXC_MSG("watch collision detected and recovery failed"), errno, this); |
} |
else { |
// recovery failed - go away |
throw InotifyException(IN_EXC_MSG("path already watched (but defined another way)"), EBUSY, this); |
} |
} |
pWatch->m_wd = wd; |
m_watches.insert(IN_WATCH_MAP::value_type(pWatch->m_wd, pWatch)); |
} |
m_paths.insert(IN_WP_MAP::value_type(pWatch->m_path, pWatch)); |
pWatch->m_pInotify = this; |
} |
void Inotify::Remove(InotifyWatch* pWatch) throw (InotifyException) |
{ |
// invalid descriptor - this case shouldn't occur - go away |
if (m_fd == -1) |
throw InotifyException(IN_EXC_MSG("invalid file descriptor"), EBUSY, this); |
// for enabled watch |
if (pWatch->m_wd != -1) { |
if (inotify_rm_watch(m_fd, pWatch->GetMask()) == -1) |
throw InotifyException(IN_EXC_MSG("removing watch failed"), errno, this); |
m_watches.erase(pWatch->m_wd); |
pWatch->m_wd = -1; |
// removing watch failed - go away |
if (inotify_rm_watch(m_fd, pWatch->m_wd) == -1) |
throw InotifyException(IN_EXC_MSG("removing watch failed"), errno, this); |
m_watches.erase(pWatch->m_wd); |
pWatch->m_wd = -1; |
} |
m_paths.erase(pWatch->m_path); |
pWatch->m_pInotify = NULL; |
} |
void Inotify::RemoveAll() |
{ |
IN_WATCH_MAP::iterator it = m_watches.begin(); |
while (it != m_watches.end()) { |
IN_WP_MAP::iterator it = m_paths.begin(); |
while (it != m_paths.end()) { |
InotifyWatch* pW = (*it).second; |
inotify_rm_watch(m_fd, pW->GetMask()); |
pW->m_wd = -1; |
if (pW->m_wd != -1) { |
inotify_rm_watch(m_fd, pW->m_wd); |
pW->m_wd = -1; |
} |
pW->m_pInotify = NULL; |
it++; |
} |
m_watches.clear(); |
m_paths.clear(); |
} |
void Inotify::WaitForEvents(bool fNoIntr) throw (InotifyException) |
257,7 → 354,7 |
while (i < len) { |
struct inotify_event* pEvt = (struct inotify_event*) &m_buf[i]; |
InotifyWatch* pW = FindWatch(pEvt->wd); |
if (pW != NULL && pW->IsEnabled()) { |
if (pW != NULL) { |
InotifyEvent evt(pEvt, pW); |
m_events.push_back(evt); |
} |
301,6 → 398,15 |
return (*it).second; |
} |
InotifyWatch* Inotify::FindWatch(const std::string& rPath) |
{ |
IN_WP_MAP::iterator it = m_paths.find(rPath); |
if (it == m_paths.end()) |
return NULL; |
return (*it).second; |
} |
void Inotify::SetNonBlock(bool fNonBlock) throw (InotifyException) |
{ |
/incron/trunk/icd-main.cpp |
---|
27,20 → 27,29 |
#include "usertable.h" |
/// Daemon yes/no |
#define DAEMON true |
/// Application name |
#define INCRON_APP_NAME "incrond" |
/// Logging options (console as fallback, log PID) |
#define INCRON_LOG_OPTS (LOG_CONS | LOG_PID) |
/// Logging facility (use CRON) |
#define INCRON_LOG_FACIL LOG_CRON |
/// User name to user table mapping definition |
typedef std::map<std::string, UserTable*> SUT_MAP; |
/// User name to user table mapping table |
SUT_MAP g_ut; |
/// Finish program yes/no |
volatile bool g_fFinish = false; |
/// Handles a signal. |
/** |
* For SIGTERM and SIGINT it sets the program finish variable. |
156,7 → 165,7 |
struct pollfd pfd; |
pfd.fd = in.GetDescriptor(); |
pfd.events = POLLIN; |
pfd.events = (short) POLLIN; |
pfd.revents = (short) 0; |
while (!g_fFinish) { |
/incron/trunk/inotify-cxx.h |
---|
30,9 → 30,13 |
#include <deque> |
#include <map> |
// Please ensure that the following headers take the right place. |
// Please ensure that the following headers take the right place |
#include <sys/inotify.h> |
// Use this if syscalls not defined |
#ifndef __NR_inotify_init |
#include <sys/inotify-syscalls.h> |
#endif // __NR_inotify_init |
/// Event struct size |
#define INOTIFY_EVENT_SIZE (sizeof(struct inotify_event)) |
318,6 → 322,18 |
return (uint32_t) m_uMask; |
} |
/// Sets the watch event mask. |
/** |
* If the watch is active (added to an instance of Inofify) |
* this method may fail due to unsuccessful re-setting |
* the watch in the kernel. |
* |
* \param[in] uMask event mask |
* |
* \throw InotifyException thrown if changing fails |
*/ |
void SetMask(uint32_t uMask) throw (InotifyException); |
/// Returns the appropriate inotify class instance. |
/** |
* \return inotify instance |
327,11 → 343,24 |
return m_pInotify; |
} |
inline void SetEnabled(bool fEnabled) |
{ |
m_fEnabled = fEnabled; |
} |
/// Enables/disables the watch. |
/** |
* If the watch is active (added to an instance of Inofify) |
* this method may fail due to unsuccessful re-setting |
* the watch in the kernel. |
* |
* Re-setting the current state has no effect. |
* |
* \param[in] fEnabled set enabled yes/no |
* |
* \throw InotifyException thrown if enabling/disabling fails |
*/ |
void SetEnabled(bool fEnabled) throw (InotifyException); |
/// Checks whether the watch is enabled. |
/** |
* \return true = enables, false = disabled |
*/ |
inline bool IsEnabled() const |
{ |
return m_fEnabled; |
351,7 → 380,10 |
/// Mapping from watch descriptors to watch objects. |
typedef std::map<int32_t, InotifyWatch*> IN_WATCH_MAP; |
/// Mapping from paths to watch objects. |
typedef std::map<std::string, InotifyWatch*> IN_WP_MAP; |
/// inotify class |
class Inotify |
{ |
421,11 → 453,14 |
/// Returns the count of watches. |
/** |
* This is the total count of all watches (regardless whether |
* enabled or not). |
* |
* \return count of watches |
*/ |
inline size_t GetWatchCount() const |
{ |
return (size_t) m_watches.size(); |
return (size_t) m_paths.size(); |
} |
/// Waits for inotify events. |
499,15 → 534,28 |
return PeekEvent(&rEvt); |
} |
/// Searches for a watch. |
/// Searches for a watch by a watch descriptor. |
/** |
* It tries to find a watch by the given descriptor. |
* |
* \param[in] iDescriptor watch descriptor |
* \return found descriptor; NULL if no such watch exists |
* \return pointer to a watch; NULL if no such watch exists |
*/ |
InotifyWatch* FindWatch(int iDescriptor); |
/// Searches for a watch by a filesystem path. |
/** |
* It tries to find a watch by the given filesystem path. |
* |
* \param[in] rPath filesystem path |
* \return pointer to a watch; NULL if no such watch exists |
* |
* \attention The path must be exactly identical to the one |
* used for the searched watch. Be careful about |
* absolute/relative and case-insensitive paths. |
*/ |
InotifyWatch* FindWatch(const std::string& rPath); |
/// Returns the file descriptor. |
/** |
* The descriptor can be used in standard low-level file |
538,9 → 586,12 |
private: |
int m_fd; ///< file descriptor |
IN_WATCH_MAP m_watches; ///< watches |
IN_WATCH_MAP m_watches; ///< watches (by descriptors) |
IN_WP_MAP m_paths; ///< watches (by paths) |
unsigned char m_buf[INOTIFY_BUFLEN]; ///< buffer for events |
std::deque<InotifyEvent> m_events; ///< event queue |
friend class InotifyWatch; |
}; |
/incron/trunk/Makefile |
---|
40,7 → 40,7 |
install: all |
[ -d $(PREFIX) ] |
useradd -M -s /sbin/nologin $(USER) |
useradd -M -s /sbin/nologin $(USER) || useradd -s /sbin/nologin $(USER) |
$(INSTALL) -m 04755 -o $(USER) incrontab $(PREFIX)/bin/ |
$(INSTALL) -m 0755 incrond $(PREFIX)/sbin/ |
$(INSTALL) -m 0755 -o $(USER) -d $(DATADIR) |