Subversion Repositories public

Compare Revisions

Ignore whitespace Rev 54 → Rev 55

/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);
}
 
211,9 → 213,9
strcpy(s, "/tmp/incron.table-XXXXXX");
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,9 → 62,7
{
IWUT_MAP::iterator it = m_maps.find(pWatch);
if (it == m_maps.end())
return;
m_maps.erase(it);
m_maps.erase(it);
}
void EventDispatcher::UnregisterAll(UserTable* pTab)
159,19 → 157,32
cmd.append(cs.substr(oldpos, pos-oldpos+1));
oldpos = pos + 2;
}
else if (cs[px] == '@') {
cmd.append(cs.substr(oldpos, pos-oldpos));
cmd.append(pW->GetPath());
oldpos = pos + 2;
}
else if (cs[px] == '#') {
cmd.append(cs.substr(oldpos, pos-oldpos));
cmd.append(rEvt.GetName());
oldpos = pos + 2;
}
else {
cmd.append(cs.substr(oldpos, pos-oldpos));
oldpos = pos + 1;
if (cs[px] == '@') { // base path
cmd.append(pW->GetPath());
oldpos = pos + 2;
}
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 {
oldpos = pos + 1;
}
}
}
else {
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_