/incron/trunk/ict-main.cpp |
---|
22,6 → 22,7 |
#include <sys/stat.h> |
#include <sys/wait.h> |
#include "incron.h" |
#include "incrontab.h" |
29,18 → 30,18 |
#define INCRON_DEFAULT_EDITOR "vim" |
const char* argp_program_version = "incrontab 0.2.2"; |
const char* argp_program_bug_address = "<bugs@aiken.cz>"; |
const char* argp_program_version = INCRON_TAB_NAME " " INCRON_VERSION; |
const char* argp_program_bug_address = INCRON_BUG_ADDRESS; |
static char doc[] = "Table manipulator for incrond (inotify cron daemon)"; |
static char doc[] = "incrontab - incron table manipulator"; |
static char args_doc[] = "FILE"; |
static struct argp_option options[] = { |
{"list", 'l', 0, 0, "List current table" }, |
{"remove", 'r', 0, 0, "Remove table completely" }, |
{"edit", 'e', 0, 0, "Edit table" }, |
{"user", 'u', "USER", 0, "Override current user" }, |
{"list", 'l', 0, 0, "List the current table" }, |
{"remove", 'r', 0, 0, "Remove the table completely" }, |
{"edit", 'e', 0, 0, "Edit the table" }, |
{"user", 'u', "USER", 0, "Override the current user" }, |
{ 0 } |
}; |
113,7 → 114,8 |
{ |
uid_t iu = geteuid(); |
seteuid(uid); |
unlink(file); |
if (unlink(file) != 0) |
perror("cannot remove temporary file"); |
seteuid(iu); |
} |
213,7 → 215,7 |
uid_t iu = geteuid(); |
if (seteuid(uid) != 0) { |
fprintf(stderr, "cannot change effective UID: %s\n", strerror(errno)); |
fprintf(stderr, "cannot change effective UID to %i: %s\n", (int) uid, strerror(errno)); |
return false; |
} |
/incron/trunk/CHANGELOG |
---|
1,5 → 1,12 |
0.3.0 2006-11-12 |
* based on inotify-cxx 0.5.2 (fixes a problem with ignoring IN_OPEN) |
* two new special symbols ($% for flags as names, $& for numeric flags) |
* whitespaces in paths now allowed (by prepending a backslash) (#0000098) |
* some changes in logging etc. |
0.2.3 2006-10-30 |
* problems with unwanted IN_NO_LOOP have been fixes (#0000097) |
* problems with unwanted IN_NO_LOOP have been fixed (#0000097) |
0.2.2 2006-10-29 |
/incron/trunk/README |
---|
22,7 → 22,7 |
2. Requirements |
* Linux kernel 2.6.13 or later (with inotify compiled in) |
* inotify headers (inotify.h, inotify-syscalls.h) installed in |
* inotify headers (inotify.h, sometimes inotify-syscalls.h) installed in |
<INCLUDE_DIR>/sys. The most common place is /usr/include/sys. |
* GCC 4.x compiler (probably works also with GCC 3.4, possibly with |
older versions too) |
68,17 → 68,25 |
$$ - a dollar sign |
$@ - the watched filesystem path (see above) |
$# - the event-related file name |
$% - the event flags (textually) |
$& - the event flags (numerically) |
The mask may additionaly contain a special symbol IN_NO_LOOP which |
disables events occurred during the event handling (to avoid loops). |
Example: You need to run program 'abc' with the full file path as |
Example 1: You need to run program 'abc' with the full file path as |
an argument every time a file is changed in /var/mail. One of |
the solutions follows: |
/var/mail IN_CLOSE_WRITE abc $@/$# |
Example 2: You need to run program 'efg' with the full file path as |
the first argument and the numeric event flags as the second one. |
It have to monitor all events on files in /tmp. Here is it: |
/tmp IN_ALL_EVENTS efg $@/$# $& |
5. Bugs, suggestions |
THIS PROGRAM IS AN ALPHA VERSION. IT PROBABLY CONTAINS BUGS AND |
THEREFORE IT IS NOT INTENDED FOR PRODUCTION USE. |
/incron/trunk/incrontab.cpp |
---|
62,24 → 62,39 |
m.append(",IN_NO_LOOP"); |
} |
ss << m_path << " " << m << " " << m_cmd; |
ss << GetSafePath(m_path) << " " << m << " " << m_cmd; |
return ss.str(); |
} |
bool InCronTabEntry::Parse(const std::string& rStr, InCronTabEntry& rEntry) |
{ |
char s1[1000], s2[1000], s3[1000]; |
unsigned long u; |
std::string s1, s2, s3; |
if (sscanf(rStr.c_str(), "%s %s %[^\n]", s1, s2, s3) != 3) |
StringTokenizer tok(rStr, ' ', '\\'); |
if (!tok.HasMoreTokens()) |
return false; |
s1 = tok.GetNextToken(true); |
if (!tok.HasMoreTokens()) |
return false; |
s2 = tok.GetNextToken(true); |
if (!tok.HasMoreTokens()) |
return false; |
tok.SetNoPrefix(); |
s3 = tok.GetRemainder(); |
SIZE len = s3.length(); |
if (len > 0 && s3[len-1] == '\n') |
s3.resize(len-1); |
rEntry.m_path = s1; |
rEntry.m_cmd = s3; |
rEntry.m_uMask = 0; |
rEntry.m_fNoLoop = false; |
if (sscanf(s2, "%lu", &u) == 1) { |
if (sscanf(s2.c_str(), "%lu", &u) == 1) { |
rEntry.m_uMask = (uint32_t) u; |
} |
else { |
96,6 → 111,26 |
return true; |
} |
std::string InCronTabEntry::GetSafePath(const std::string& rPath) |
{ |
std::ostringstream stream; |
SIZE len = rPath.length(); |
for (SIZE i = 0; i < len; i++) { |
if (rPath[i] == ' ') { |
stream << "\\ "; |
} |
else if (rPath[i] == '\\') { |
stream << "\\\\"; |
} |
else { |
stream << rPath[i]; |
} |
} |
return stream.str(); |
} |
bool InCronTab::Load(const std::string& rPath) |
{ |
m_tab.clear(); |
181,3 → 216,5 |
return s; |
} |
/incron/trunk/inotify-cxx.cpp |
---|
35,6 → 35,7 |
}) |
int32_t InotifyEvent::GetDescriptor() const |
{ |
return m_pWatch != NULL // if watch exists |
54,6 → 55,8 |
return IN_CLOSE_WRITE; |
else if (rName == "IN_CLOSE_NOWRITE") |
return IN_CLOSE_NOWRITE; |
else if (rName == "IN_OPEN") |
return IN_OPEN; |
else if (rName == "IN_MOVED_FROM") |
return IN_MOVED_FROM; |
else if (rName == "IN_MOVED_TO") |
/incron/trunk/icd-main.cpp |
---|
23,16 → 23,14 |
#include <sys/poll.h> |
#include "inotify-cxx.h" |
#include "incron.h" |
#include "incrontab.h" |
#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) |
128,9 → 126,9 |
*/ |
int main(int argc, char** argv) |
{ |
openlog(INCRON_APP_NAME, INCRON_LOG_OPTS, INCRON_LOG_FACIL); |
openlog(INCRON_DAEMON_NAME, INCRON_LOG_OPTS, INCRON_LOG_FACIL); |
syslog(LOG_NOTICE, "starting service"); |
syslog(LOG_NOTICE, "starting service (version %s, built on %s %s)", INCRON_VERSION, __DATE__, __TIME__); |
try { |
Inotify in; |
/incron/trunk/incrontab.h |
---|
103,6 → 103,21 |
return m_fNoLoop; |
} |
/// Add backslashes before spaces in the source path. |
/** |
* It also adds backslashes before all original backslashes |
* of course. |
* |
* The source string is not modified and a copy is returned |
* instead. |
* |
* This method is intended to be used for paths in user tables. |
* |
* \param[in] rPath path to be modified |
* \return modified path |
*/ |
static std::string GetSafePath(const std::string& rPath); |
protected: |
std::string m_path; ///< watch path |
uint32_t m_uMask; ///< event mask |
/incron/trunk/TODO |
---|
1,3 → 1,4 |
Currently pending tasks: |
*** nothing to do *** |
#0000101 - Temporary files not removed |
#0000103 - User overriding doesn't work |
/incron/trunk/strtok.cpp |
---|
20,31 → 20,121 |
*/ |
#include <sstream> |
#include "strtok.h" |
typedef std::string::size_type SIZE; |
StringTokenizer::StringTokenizer(const std::string& rStr, char cDelim) |
StringTokenizer::StringTokenizer(const std::string& rStr, char cDelim, char cPrefix) |
{ |
m_str = rStr; |
m_cDelim = cDelim; |
m_cPrefix = cPrefix; |
m_pos = 0; |
m_len = rStr.length(); |
} |
std::string StringTokenizer::GetNextToken() |
std::string StringTokenizer::GetNextToken(bool fSkipEmpty) |
{ |
std::string s; |
do { |
_GetNextToken(s, true); |
} while (fSkipEmpty && s.empty() && m_pos < m_len); |
return s; |
} |
std::string StringTokenizer::GetNextTokenRaw(bool fSkipEmpty) |
{ |
std::string s; |
do { |
_GetNextToken(s, false); |
} while (fSkipEmpty && s.empty() && m_pos < m_len); |
return s; |
} |
std::string StringTokenizer::GetRemainder() |
{ |
return m_cPrefix == '\0' |
? m_str.substr(m_pos) |
: StripPrefix(m_str.c_str() + m_pos, m_len - m_pos); |
} |
std::string StringTokenizer::StripPrefix(const char* s, SIZE cnt) |
{ |
std::ostringstream stream; |
SIZE pos = 0; |
while (pos < cnt) { |
if (s[pos] == m_cPrefix) { |
if ((pos < cnt - 1) && s[pos+1] == m_cPrefix) { |
stream << m_cPrefix; |
pos++; |
} |
} |
else { |
stream << s[pos]; |
} |
pos++; |
} |
return stream.str(); |
} |
void StringTokenizer::_GetNextToken(std::string& rToken, bool fStripPrefix) |
{ |
if (m_cPrefix == '\0') { |
_GetNextTokenNoPrefix(rToken); |
} |
else { |
_GetNextTokenWithPrefix(rToken); |
if (fStripPrefix) |
rToken = StripPrefix(rToken.c_str(), rToken.length()); |
} |
} |
void StringTokenizer::_GetNextTokenNoPrefix(std::string& rToken) |
{ |
for (SIZE i=m_pos; i<m_len; i++) { |
if (m_str[i] == m_cDelim) { |
s = m_str.substr(m_pos, i - m_pos); |
rToken = m_str.substr(m_pos, i - m_pos); |
m_pos = i + 1; |
return s; |
return; |
} |
} |
s = m_str.substr(m_pos); |
rToken = m_str.substr(m_pos); |
m_pos = m_len; |
return s; |
} |
void StringTokenizer::_GetNextTokenWithPrefix(std::string& rToken) |
{ |
int pref = 0; |
for (SIZE i=m_pos; i<m_len; i++) { |
if (m_str[i] == m_cDelim) { |
if (pref == 0) { |
rToken = m_str.substr(m_pos, i - m_pos); |
m_pos = i + 1; |
return; |
} |
else { |
pref = 0; |
} |
} |
else if (m_str[i] == m_cPrefix) { |
if (pref == 1) |
pref = 0; |
else |
pref = 1; |
} |
else { |
pref = 0; |
} |
} |
rToken = m_str.substr(m_pos); |
m_pos = m_len; |
} |
/incron/trunk/inotify-cxx.h |
---|
31,6 → 31,7 |
#include <map> |
// Please ensure that the following headers take the right place |
#include <sys/syscall.h> |
#include <sys/inotify.h> |
// Use this if syscalls not defined |
/incron/trunk/usertable.cpp |
---|
62,8 → 62,6 |
{ |
IWUT_MAP::iterator it = m_maps.find(pWatch); |
if (it == m_maps.end()) |
return; |
m_maps.erase(it); |
} |
159,21 → 157,34 |
cmd.append(cs.substr(oldpos, pos-oldpos+1)); |
oldpos = pos + 2; |
} |
else if (cs[px] == '@') { |
else { |
cmd.append(cs.substr(oldpos, pos-oldpos)); |
if (cs[px] == '@') { // base path |
cmd.append(pW->GetPath()); |
oldpos = pos + 2; |
} |
else if (cs[px] == '#') { |
cmd.append(cs.substr(oldpos, pos-oldpos)); |
else if (cs[px] == '#') { // file name |
cmd.append(rEvt.GetName()); |
oldpos = pos + 2; |
} |
else if (cs[px] == '%') { // mask symbols |
std::string s; |
rEvt.DumpTypes(s); |
cmd.append(s); |
oldpos = pos + 2; |
} |
else if (cs[px] == '&') { // numeric mask |
char* s; |
asprintf(&s, "%u", (unsigned) rEvt.GetMask()); |
cmd.append(s); |
free(s); |
oldpos = pos + 2; |
} |
else { |
cmd.append(cs.substr(oldpos, pos-oldpos)); |
oldpos = pos + 1; |
} |
} |
} |
else { |
cmd.append(cs.substr(oldpos, pos-oldpos)); |
oldpos = pos + 1; |
241,7 → 252,7 |
if (rCmd.empty()) |
return false; |
StringTokenizer tok(rCmd, ' '); |
StringTokenizer tok(rCmd, ' ', '\\'); |
std::deque<std::string> args; |
while (tok.HasMoreTokens()) { |
args.push_back(tok.GetNextToken()); |
/incron/trunk/strtok.h |
---|
26,6 → 26,8 |
#include <string> |
typedef std::string::size_type SIZE; |
/// Simple string tokenizer class. |
/** |
* This class implements a string tokenizer. It splits a string |
32,12 → 34,22 |
* by a character to a number of elements (tokens) which are |
* provided sequentially. |
* |
* All operations are made on the original string itself. |
* The implementation is not ready to handle any changes of the |
* string. |
* All operations are made on a copy of the original string |
* (which may be in fact a copy-on-write instance). |
* |
* The original string is left unchanged. All tokens are returned |
* as newly created strings. |
* |
* There is possibility to specify a prefix character which |
* causes the consecutive character is not considered as |
* a delimiter. If you don't specify this character (or specify |
* the NUL character, 0x00) this feature is disabled. The mostly |
* used prefix is a backslash ('\'). |
* |
* This class is not thread-safe. |
* |
* Performance note: This class is currently not intended |
* to be very fast. Speed optimizations will be done later. |
*/ |
class StringTokenizer |
{ |
48,8 → 60,10 |
* |
* \param[in] rStr string for tokenizing |
* \param[in] cDelim delimiter (separator) character |
* \param[in] cPrefix character which is prepended if a |
* character must not separate tokens |
*/ |
StringTokenizer(const std::string& rStr, char cDelim = ','); |
StringTokenizer(const std::string& rStr, char cDelim = ',', char cPrefix = '\0'); |
/// Destructor. |
~StringTokenizer() {} |
65,15 → 79,50 |
/// Returns the next token. |
/** |
* If a prefix is defined it is stripped from the returned |
* string (e.g. 'abc\ def' is transformed to 'abc def' |
* while the prefix is '\'). |
* |
* \param[in] fSkipEmpty skip empty strings (more consecutive delimiters) |
* \return next token or "" if no more tokens available |
* |
* \sa GetNextTokenRaw() |
*/ |
std::string GetNextToken(); |
std::string GetNextToken(bool fSkipEmpty = false); |
/// Returns the next token. |
/** |
* This method always returns an unmodified string even |
* if it contains prefix characters. |
* |
* \param[in] fSkipEmpty skip empty strings (more consecutive delimiters) |
* \return next token or "" if no more tokens available |
* |
* \sa GetNextToken() |
*/ |
std::string GetNextTokenRaw(bool fSkipEmpty = false); |
/// Returns the remainder of the source string. |
/** |
* This method returns everything what has not been |
* processed (tokenized) yet and moves the current |
* position to the end of the string. |
* |
* If a prefix is defined it is stripped from |
* the returned string. |
* |
* \return remainder string |
*/ |
std::string GetRemainder(); |
/// Sets a delimiter (separator) character. |
/** |
* The new delimiter has effect only to tokens returned later; |
* the position in the string is not affected. |
* |
* If you specify a NUL character (0x00) here the prefix |
* will not be used. |
* |
* \param[in] cDelim delimiter character |
*/ |
inline void SetDelimiter(char cDelim) |
90,6 → 139,40 |
return m_cDelim; |
} |
/// Sets a prefix character. |
/** |
* The new prefix has effect only to tokens returned later; |
* the position in the string is not affected. |
* |
* \param[in] cPrefix prefix character |
* |
* \sa SetNoPrefix() |
*/ |
inline void SetPrefix(char cPrefix) |
{ |
m_cPrefix = cPrefix; |
} |
/// Returns the prefix character. |
/** |
* \return prefix character |
*/ |
inline char GetPrefix() const |
{ |
return m_cPrefix; |
} |
/// Sets the prefix to 'no prefix'. |
/** |
* Calling this method is equivalent to SetPrefix((char) 0). |
* |
* \sa SetPrefix() |
*/ |
inline void SetNoPrefix() |
{ |
SetPrefix('\0'); |
} |
/// Resets the tokenizer. |
/** |
* Re-initializes tokenizing to the start of the string. |
102,8 → 185,46 |
private: |
std::string m_str; ///< tokenized string |
char m_cDelim; ///< delimiter character |
char m_cPrefix; ///< prefix character |
std::string::size_type m_pos; ///< current position |
std::string::size_type m_len; ///< string length |
/// Strips all prefix characters. |
/** |
* \param[in] s source string |
* \param[in] cnt string length |
* \return modified string |
*/ |
std::string StripPrefix(const char* s, SIZE cnt); |
/// Extracts the next token (internal method). |
/** |
* The extracted token may be empty. |
* |
* \param[out] rToken extracted token |
* \param[in] fStripPrefix strip prefix characters yes/no |
*/ |
void _GetNextToken(std::string& rToken, bool fStripPrefix); |
/// Extracts the next token (internal method). |
/** |
* This method does no checking about the prefix character. |
* |
* The extracted token may be empty. |
* |
* \param[out] rToken extracted token |
*/ |
void _GetNextTokenNoPrefix(std::string& rToken); |
/// Extracts the next token (internal method). |
/** |
* This method does checking about the prefix character. |
* |
* The extracted token may be empty. |
* |
* \param[out] rToken extracted token |
*/ |
void _GetNextTokenWithPrefix(std::string& rToken); |
}; |
/incron/trunk/Makefile |
---|
56,10 → 56,10 |
.POSIX: |
icd-main.o: icd-main.cpp inotify-cxx.h incrontab.h usertable.h |
icd-main.o: icd-main.cpp inotify-cxx.h incrontab.h usertable.h incron.h |
incrontab.o: incrontab.cpp incrontab.h inotify-cxx.h strtok.h |
inotify-cxx.o: inotify-cxx.cpp inotify-cxx.h |
usertable.o: usertable.cpp usertable.h strtok.h |
ict-main.o: ict-main.cpp incrontab.h |
ict-main.o: ict-main.cpp incrontab.h incron.h |
strtok.o: strtok.cpp strtok.h |
/incron/trunk/incron.h |
---|
0,0 → 1,36 |
/// inotify cron basic definition file |
/** |
* \file incron.h |
* |
* inotify cron system |
* |
* Copyright (C) 2006 Lukas Jelinek, <lukas@aiken.cz> |
* |
* This program is free software; you can use it, redistribute |
* it and/or modify it under the terms of the GNU General Public |
* License, version 2 (see LICENSE-GPL). |
* |
*/ |
#ifndef _INCRON_H_ |
#define _INCRON_H_ |
/// Common application name |
#define INCRON_NAME "incron" |
/// Daemon name |
#define INCRON_DAEMON_NAME "incrond" |
/// Table manipulator name |
#define INCRON_TAB_NAME "incrontab" |
/// Application version (release) |
#define INCRON_VERSION "0.3.0" |
/// Address for sending bugs |
#define INCRON_BUG_ADDRESS "<bugs@aiken.cz>" |
#endif //_INCRON_H_ |