/incron/tags/incron-0.3.0/ict-main.cpp |
---|
0,0 → 1,416 |
/// inotify cron table manipulator main file |
/** |
* \file ict-main.cpp |
* |
* 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). |
* |
*/ |
#include <argp.h> |
#include <pwd.h> |
#include <string> |
#include <stdio.h> |
#include <unistd.h> |
#include <sys/stat.h> |
#include <sys/wait.h> |
#include "incron.h" |
#include "incrontab.h" |
// #define INCRON_DEFAULT_EDITOR "nano" // for vim haters like me ;-) |
#define INCRON_DEFAULT_EDITOR "vim" |
const char* argp_program_version = INCRON_TAB_NAME " " INCRON_VERSION; |
const char* argp_program_bug_address = INCRON_BUG_ADDRESS; |
static char doc[] = "incrontab - incron table manipulator"; |
static char args_doc[] = "FILE"; |
static struct argp_option options[] = { |
{"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 } |
}; |
/// incrontab operations |
typedef enum |
{ |
OPER_NONE, /// nothing |
OPER_LIST, /// list table |
OPER_REMOVE, /// remove table |
OPER_EDIT /// edit table |
} InCronTab_Operation_t; |
/// incrontab arguments |
struct arguments |
{ |
char *user; /// user name |
int oper; /// operation code |
char *file; /// file to import |
}; |
/// 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; |
switch (key) { |
case 'l': |
arguments->oper = OPER_LIST; |
break; |
case 'r': |
arguments->oper = OPER_REMOVE; |
break; |
case 'e': |
arguments->oper = OPER_EDIT; |
break; |
case 'u': |
arguments->user = arg; |
break; |
case ARGP_KEY_ARG: |
if (state->arg_num >= 1) |
argp_usage(state); |
arguments->file = arg; |
break; |
case ARGP_KEY_END: |
break; |
default: |
return ARGP_ERR_UNKNOWN; |
} |
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(); |
seteuid(uid); |
if (unlink(file) != 0) |
perror("cannot remove temporary file"); |
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; |
std::string s(path); |
if (s == "-") |
s = "/dev/stdin"; |
if (!tab.Load(s)) { |
fprintf(stderr, "cannot load table from file: %s\n", path); |
return false; |
} |
std::string out(InCronTab::GetUserTablePath(user)); |
if (!tab.Save(out)) { |
fprintf(stderr, "cannot create table for user: %s\n", user); |
return false; |
} |
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)); |
if (unlink(tp.c_str()) != 0 && errno != ENOENT) { |
fprintf(stderr, "cannot remove table for user: %s\n", user); |
return false; |
} |
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)); |
if (access(tp.c_str(), R_OK) != 0) { |
if (errno == ENOENT) { |
fprintf(stderr, "no table for %s\n", user); |
return true; |
} |
else { |
fprintf(stderr, "cannot read table for %s: %s\n", user, strerror(errno)); |
return false; |
} |
} |
std::string cmd("cat "); |
cmd.append(tp); |
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)); |
struct passwd* ppwd = getpwnam(user); |
if (ppwd == NULL) { |
fprintf(stderr, "cannot find user %s: %s\n", user, strerror(errno)); |
return false; |
} |
uid_t uid = ppwd->pw_uid; |
char s[NAME_MAX]; |
strcpy(s, "/tmp/incron.table-XXXXXX"); |
uid_t iu = geteuid(); |
if (seteuid(uid) != 0) { |
fprintf(stderr, "cannot change effective UID to %i: %s\n", (int) uid, strerror(errno)); |
return false; |
} |
int fd = mkstemp(s); |
if (fd == -1) { |
fprintf(stderr, "cannot create temporary file: %s\n", strerror(errno)); |
return false; |
} |
if (fchmod(fd, 0644) != 0) { |
fprintf(stderr, "cannot change mode of temporary file: %s\n", strerror(errno)); |
close(fd); |
unlink_suid(s, uid); |
return false; |
} |
if (seteuid(iu) != 0) { |
fprintf(stderr, "cannot change effective UID: %s\n", strerror(errno)); |
close(fd); |
unlink_suid(s, uid); |
return false; |
} |
FILE* out = fdopen(fd, "w"); |
if (out == NULL) { |
fprintf(stderr, "cannot write to temporary file: %s\n", strerror(errno)); |
close(fd); |
unlink_suid(s, uid); |
return false; |
} |
FILE* in = fopen(tp.c_str(), "r"); |
if (in == NULL) { |
if (errno == ENOENT) { |
in = fopen("/dev/null", "r"); |
if (in == NULL) { |
fprintf(stderr, "cannot get empty table for %s: %s\n", user, strerror(errno)); |
fclose(out); |
unlink_suid(s, uid); |
return false; |
} |
} |
else { |
fprintf(stderr, "cannot read old table for %s: %s\n", user, strerror(errno)); |
fclose(out); |
unlink_suid(s, uid); |
return false; |
} |
} |
char buf[1024]; |
while (fgets(buf, 1024, in) != NULL) { |
fputs(buf, out); |
} |
fclose(in); |
fclose(out); |
struct stat st; |
if (stat(s, &st) != 0) { |
fprintf(stderr, "cannot stat temporary file: %s\n", strerror(errno)); |
unlink_suid(s, uid); |
return false; |
} |
time_t mt = st.st_mtime; |
const char* e = getenv("EDITOR"); |
if (e == NULL) |
e = INCRON_DEFAULT_EDITOR; |
pid_t pid = fork(); |
if (pid == 0) { |
if (setuid(uid) != 0) { |
fprintf(stderr, "cannot set user %s: %s\n", user, strerror(errno)); |
return false; |
} |
execlp(e, e, s, NULL); |
_exit(1); |
} |
else if (pid > 0) { |
int status; |
if (wait(&status) != pid) { |
perror("error while waiting for editor"); |
unlink_suid(s, uid); |
return false; |
} |
if (!(WIFEXITED(status)) || WEXITSTATUS(status) != 0) { |
perror("editor finished with error"); |
unlink_suid(s, uid); |
return false; |
} |
} |
else { |
perror("cannot start editor"); |
unlink_suid(s, uid); |
return false; |
} |
if (stat(s, &st) != 0) { |
fprintf(stderr, "cannot stat temporary file: %s\n", strerror(errno)); |
unlink_suid(s, uid); |
return false; |
} |
if (st.st_mtime == mt) { |
fprintf(stderr, "table unchanged\n"); |
unlink_suid(s, uid); |
return true; |
} |
InCronTab ict; |
if (!ict.Load(s) || !ict.Save(tp)) { |
fprintf(stderr, "cannot move temporary table: %s\n", strerror(errno)); |
unlink(s); |
return false; |
} |
fprintf(stderr, "table updated\n"); |
unlink_suid(s, uid); |
return true; |
} |
int main(int argc, char** argv) |
{ |
struct arguments arguments; |
arguments.user = NULL; |
arguments.oper = OPER_NONE; |
arguments.file = NULL; |
argp_parse (&argp, argc, argv, 0, 0, &arguments); |
if (arguments.file != NULL && arguments.oper != OPER_NONE) { |
fprintf(stderr, "invalid arguments - specify source file or operation\n"); |
return 1; |
} |
if (arguments.file == NULL && arguments.oper == OPER_NONE) { |
fprintf(stderr, "invalid arguments - specify source file or operation\n"); |
return 1; |
} |
uid_t uid = getuid(); |
if (uid != 0 && arguments.user != NULL) { |
fprintf(stderr, "cannot access table for user %s: permission denied\n", arguments.user); |
return 1; |
} |
struct passwd pwd; |
if (arguments.user == NULL) { |
struct passwd* ppwd = getpwuid(uid); |
if (ppwd == NULL) { |
fprintf(stderr, "cannot determine current user\n"); |
return 1; |
} |
memcpy(&pwd, ppwd, sizeof(pwd)); |
arguments.user = pwd.pw_name; |
} |
else if (getpwnam(arguments.user) == NULL) { |
fprintf(stderr, "user %s not found\n", arguments.user); |
return 1; |
} |
if (!InCronTab::CheckUser(arguments.user)) { |
fprintf(stderr, "user %s is not allowed to use incron\n", arguments.user); |
return 1; |
} |
switch (arguments.oper) { |
case OPER_NONE: |
fprintf(stderr, "copying table from file: %s\n", arguments.file); |
if (!copy_from_file(arguments.file, arguments.user)) |
return 1; |
break; |
case OPER_LIST: |
if (!list_table(arguments.user)) |
return 1; |
break; |
case OPER_REMOVE: |
fprintf(stderr, "removing table for user %s\n", arguments.user); |
if (!remove_table(arguments.user)) |
return 1; |
break; |
case OPER_EDIT: |
if (!edit_table(arguments.user)) |
return 1; |
break; |
default: |
fprintf(stderr, "invalid usage\n"); |
return 1; |
} |
return 0; |
} |
/incron/tags/incron-0.3.0/CHANGELOG |
---|
0,0 → 1,34 |
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 fixed (#0000097) |
0.2.2 2006-10-29 |
* based on inotify-cxx 0.5.0 |
* 'uncleaned children' bug has been fixed (#0000095) |
* memory leak (child process arguments) has been fixed (#0000096) |
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) |
* loop avoidance can be used |
* more documentation in the code |
0.1.0 2006-09-15 |
* first alpha version |
/incron/tags/incron-0.3.0/README |
---|
0,0 → 1,105 |
inotify cron system |
(c) Lukas Jelinek, 2006 |
1. About |
2. Requirements |
3. How to use |
4. Bugs, suggestions |
5. Licensing |
6. Documentation |
======================================================================== |
1. About |
This program is the "inotify cron" system. It consist of a daemon and |
a table manipulator. You can use it a similar way as the regular cron. |
The difference is that the inotify cron handles filesystem events |
rather than time periods. |
2. Requirements |
* Linux kernel 2.6.13 or later (with inotify compiled 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) |
3. How to build |
Because this version is very early it does not contain a standard |
portable build mechanism. There is only a Makefile which must be |
modified manually. On many Linux systems you need not to change |
anything. |
Please review the Makefile BEFORE you type 'make'. Especially |
check the PREFIX and other common variables. If done you can |
now build the files ('make'). |
The binaries must be of course installed as root. Note that the |
installer creates a special user called 'incron' which manages |
the incron tables. |
4. How to use |
The incron daemon (incrond) must be run under root (typically from |
runlevel script etc.). It loads the current user tables and hooks |
them for later changes. |
The incron table manipulator may be run under any regular user |
since it SUIDs. For manipulation with the tables use basically |
the same syntax as for the crontab program. You can import a table, |
remove and edit the current table. |
The user table rows have the following syntax: |
<path> <mask> <command> |
Where: |
<path> is a filesystem path (currently avoid whitespaces!) |
<mask> is a symbolic (see inotify.h; use commas for separating |
symbols) or numeric mask for events |
<command> is an application or script to run on the events |
The command may contain these wildcards: |
$$ - 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 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. |
If you find a bug or have a suggestion how to improve the program, |
please use the bug tracking system at http://bts.aiken.cz. |
6. Licensing |
This program is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public License, |
version 2 (see LICENSE-GPL). |
Some parts may be also licensed covere by other licenses. |
Please look into the source files for detailed information. |
/incron/tags/incron-0.3.0/incrontab.cpp |
---|
0,0 → 1,220 |
/// inotify cron table manipulator classes implementation |
/** |
* \file incrontab.cpp |
* |
* 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). |
* |
*/ |
#include <sstream> |
#include <stdio.h> |
#include <errno.h> |
#include "inotify-cxx.h" |
#include "incrontab.h" |
/// Allowed users |
#define INCRON_ALLOW_PATH "/etc/incron.allow" |
/// Denied users |
#define INCRON_DENY_PATH "/etc/incron.deny" |
InCronTabEntry::InCronTabEntry() |
: m_uMask(0), |
m_fNoLoop(false) |
{ |
} |
InCronTabEntry::InCronTabEntry(const std::string& rPath, uint32_t uMask, const std::string& rCmd) |
: m_path(rPath), |
m_uMask(uMask), |
m_cmd(rCmd) |
{ |
} |
std::string InCronTabEntry::ToString() const |
{ |
std::ostringstream ss; |
std::string m; |
InotifyEvent::DumpTypes(m_uMask, m); |
if (m.empty()) { |
m = m_fNoLoop ? "IN_NO_LOOP" : "0"; |
} |
else { |
if (m_fNoLoop) |
m.append(",IN_NO_LOOP"); |
} |
ss << GetSafePath(m_path) << " " << m << " " << m_cmd; |
return ss.str(); |
} |
bool InCronTabEntry::Parse(const std::string& rStr, InCronTabEntry& rEntry) |
{ |
unsigned long u; |
std::string s1, s2, s3; |
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.c_str(), "%lu", &u) == 1) { |
rEntry.m_uMask = (uint32_t) u; |
} |
else { |
StringTokenizer tok(s2); |
while (tok.HasMoreTokens()) { |
std::string s(tok.GetNextToken()); |
if (s == "IN_NO_LOOP") |
rEntry.m_fNoLoop = true; |
else |
rEntry.m_uMask |= InotifyEvent::GetMaskByName(s); |
} |
} |
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(); |
FILE* f = fopen(rPath.c_str(), "r"); |
if (f == NULL) |
return false; |
char s[1000]; |
InCronTabEntry e; |
while (fgets(s, 1000, f) != NULL) { |
if (InCronTabEntry::Parse(s, e)) { |
m_tab.push_back(e); |
} |
} |
fclose(f); |
return true; |
} |
bool InCronTab::Save(const std::string& rPath) |
{ |
FILE* f = fopen(rPath.c_str(), "w"); |
if (f == NULL) |
return false; |
std::deque<InCronTabEntry>::iterator it = m_tab.begin(); |
while (it != m_tab.end()) { |
fputs((*it).ToString().c_str(), f); |
fputs("\n", f); |
it++; |
} |
fclose(f); |
return true; |
} |
bool InCronTab::CheckUser(const std::string& rUser) |
{ |
char s[100], u[100]; |
FILE* f = fopen(INCRON_ALLOW_PATH, "r"); |
if (f == NULL) { |
if (errno == ENOENT) { |
f = fopen(INCRON_DENY_PATH, "r"); |
if (f == NULL) { |
return errno == ENOENT; |
} |
while (fgets(s, 100, f) != NULL) { |
if (sscanf(s, "%s", u) == 1) { |
if (rUser == u) { |
fclose(f); |
return false; |
} |
} |
} |
fclose(f); |
return true; |
} |
return false; |
} |
while (fgets(s, 100, f) != NULL) { |
if (sscanf(s, "%s", u) == 1) { |
if (rUser == u) { |
fclose(f); |
return true; |
} |
} |
} |
fclose(f); |
return false; |
} |
std::string InCronTab::GetUserTablePath(const std::string& rUser) |
{ |
std::string s(INCRON_TABLE_BASE); |
s.append(rUser); |
return s; |
} |
/incron/tags/incron-0.3.0/inotify-cxx.cpp |
---|
0,0 → 1,510 |
/// inotify C++ interface implementation |
/** |
* \file inotify-cxx.cpp |
* |
* inotify C++ interface |
* |
* Copyright (C) 2006 Lukas Jelinek <lukas@aiken.cz> |
* |
* This program is free software; you can redistribute it and/or |
* modify it under the terms of one of the following licenses: |
* |
* \li 1. X11-style license (see LICENSE-X11) |
* \li 2. GNU Lesser General Public License, version 2.1 (see LICENSE-LGPL) |
* \li 3. GNU General Public License, version 2 (see LICENSE-GPL) |
* |
* If you want to help with choosing the best license for you, |
* please visit http://www.gnu.org/licenses/license-list.html. |
* |
*/ |
#include <errno.h> |
#include <unistd.h> |
#include <fcntl.h> |
#include "inotify-cxx.h" |
/// dump separator (between particular entries) |
#define DUMP_SEP \ |
({ \ |
if (!rStr.empty()) { \ |
rStr.append(","); \ |
} \ |
}) |
int32_t InotifyEvent::GetDescriptor() const |
{ |
return m_pWatch != NULL // if watch exists |
? m_pWatch->GetDescriptor() // return its descriptor |
: -1; // else return -1 |
} |
uint32_t InotifyEvent::GetMaskByName(const std::string& rName) |
{ |
if (rName == "IN_ACCESS") |
return IN_ACCESS; |
else if (rName == "IN_MODIFY") |
return IN_MODIFY; |
else if (rName == "IN_ATTRIB") |
return IN_ATTRIB; |
else if (rName == "IN_CLOSE_WRITE") |
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") |
return IN_MOVED_TO; |
else if (rName == "IN_CREATE") |
return IN_CREATE; |
else if (rName == "IN_DELETE") |
return IN_DELETE; |
else if (rName == "IN_DELETE_SELF") |
return IN_DELETE_SELF; |
else if (rName == "IN_UNMOUNT") |
return IN_UNMOUNT; |
else if (rName == "IN_Q_OVERFLOW") |
return IN_Q_OVERFLOW; |
else if (rName == "IN_IGNORED") |
return IN_IGNORED; |
else if (rName == "IN_CLOSE") |
return IN_CLOSE; |
else if (rName == "IN_MOVE") |
return IN_MOVE; |
else if (rName == "IN_ISDIR") |
return IN_ISDIR; |
else if (rName == "IN_ONESHOT") |
return IN_ONESHOT; |
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; |
} |
void InotifyEvent::DumpTypes(uint32_t uValue, std::string& rStr) |
{ |
rStr = ""; |
if (IsType(uValue, IN_ALL_EVENTS)) { |
rStr.append("IN_ALL_EVENTS"); |
} |
else { |
if (IsType(uValue, IN_ACCESS)) { |
DUMP_SEP; |
rStr.append("IN_ACCESS"); |
} |
if (IsType(uValue, IN_MODIFY)) { |
DUMP_SEP; |
rStr.append("IN_MODIFY"); |
} |
if (IsType(uValue, IN_ATTRIB)) { |
DUMP_SEP; |
rStr.append("IN_ATTRIB"); |
} |
if (IsType(uValue, IN_CREATE)) { |
DUMP_SEP; |
rStr.append("IN_CREATE"); |
} |
if (IsType(uValue, IN_DELETE)) { |
DUMP_SEP; |
rStr.append("IN_DELETE"); |
} |
if (IsType(uValue, IN_DELETE_SELF)) { |
DUMP_SEP; |
rStr.append("IN_DELETE_SELF"); |
} |
if (IsType(uValue, IN_OPEN)) { |
DUMP_SEP; |
rStr.append("IN_OPEN"); |
} |
if (IsType(uValue, IN_CLOSE)) { |
DUMP_SEP; |
rStr.append("IN_CLOSE"); |
} |
else { |
if (IsType(uValue, IN_CLOSE_WRITE)) { |
DUMP_SEP; |
rStr.append("IN_CLOSE_WRITE"); |
} |
if (IsType(uValue, IN_CLOSE_NOWRITE)) { |
DUMP_SEP; |
rStr.append("IN_CLOSE_NOWRITE"); |
} |
} |
if (IsType(uValue, IN_MOVE)) { |
DUMP_SEP; |
rStr.append("IN_MOVE"); |
} |
else { |
if (IsType(uValue, IN_MOVED_FROM)) { |
DUMP_SEP; |
rStr.append("IN_MOVED_FROM"); |
} |
if (IsType(uValue, IN_MOVED_TO)) { |
DUMP_SEP; |
rStr.append("IN_MOVED_TO"); |
} |
} |
} |
if (IsType(uValue, IN_UNMOUNT)) { |
DUMP_SEP; |
rStr.append("IN_UNMOUNT"); |
} |
if (IsType(uValue, IN_Q_OVERFLOW)) { |
DUMP_SEP; |
rStr.append("IN_Q_OVERFLOW"); |
} |
if (IsType(uValue, IN_IGNORED)) { |
DUMP_SEP; |
rStr.append("IN_IGNORED"); |
} |
if (IsType(uValue, IN_ISDIR)) { |
DUMP_SEP; |
rStr.append("IN_ISDIR"); |
} |
if (IsType(uValue, IN_ONESHOT)) { |
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 |
{ |
DumpTypes(m_uMask, rStr); |
} |
void InotifyWatch::SetMask(uint32_t uMask) throw (InotifyException) |
{ |
IN_WRITE_BEGIN |
if (m_wd != -1) { |
int wd = inotify_add_watch(m_pInotify->GetDescriptor(), m_path.c_str(), uMask); |
if (wd != m_wd) { |
IN_WRITE_END_NOTHROW |
throw InotifyException(IN_EXC_MSG("changing mask failed"), wd == -1 ? errno : EINVAL, this); |
} |
} |
m_uMask = uMask; |
IN_WRITE_END |
} |
void InotifyWatch::SetEnabled(bool fEnabled) throw (InotifyException) |
{ |
IN_WRITE_BEGIN |
if (fEnabled == m_fEnabled) { |
IN_WRITE_END_NOTHROW |
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) { |
IN_WRITE_END_NOTHROW |
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) { |
IN_WRITE_END_NOTHROW |
throw InotifyException(IN_EXC_MSG("disabling watch failed"), errno, this); |
} |
m_pInotify->m_watches.erase(m_wd); |
m_wd = -1; |
} |
} |
m_fEnabled = fEnabled; |
IN_WRITE_END |
} |
Inotify::Inotify() throw (InotifyException) |
{ |
IN_LOCK_INIT |
m_fd = inotify_init(); |
if (m_fd == -1) { |
IN_LOCK_DONE |
throw InotifyException(IN_EXC_MSG("inotify init failed"), errno, NULL); |
} |
} |
Inotify::~Inotify() |
{ |
Close(); |
IN_LOCK_DONE |
} |
void Inotify::Close() |
{ |
IN_WRITE_BEGIN |
if (m_fd != -1) { |
RemoveAll(); |
close(m_fd); |
m_fd = -1; |
} |
IN_WRITE_END |
} |
void Inotify::Add(InotifyWatch* pWatch) throw (InotifyException) |
{ |
IN_WRITE_BEGIN |
// invalid descriptor - this case shouldn't occur - go away |
if (m_fd == -1) { |
IN_WRITE_END_NOTHROW |
throw InotifyException(IN_EXC_MSG("invalid file descriptor"), EBUSY, this); |
} |
// this path already watched - go away |
if (FindWatch(pWatch->GetPath()) != NULL) { |
IN_WRITE_END_NOTHROW |
throw InotifyException(IN_EXC_MSG("path already watched"), EBUSY, this); |
} |
// for enabled watch |
if (pWatch->IsEnabled()) { |
// 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) { |
IN_WRITE_END_NOTHROW |
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) { |
IN_WRITE_END_NOTHROW |
throw InotifyException(IN_EXC_MSG("watch collision detected and recovery failed"), errno, this); |
} |
else { |
// recovery failed - go away |
IN_WRITE_END_NOTHROW |
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; |
IN_WRITE_END |
} |
void Inotify::Remove(InotifyWatch* pWatch) throw (InotifyException) |
{ |
IN_WRITE_BEGIN |
// invalid descriptor - this case shouldn't occur - go away |
if (m_fd == -1) { |
IN_WRITE_END_NOTHROW |
throw InotifyException(IN_EXC_MSG("invalid file descriptor"), EBUSY, this); |
} |
// for enabled watch |
if (pWatch->m_wd != -1) { |
// removing watch failed - go away |
if (inotify_rm_watch(m_fd, pWatch->m_wd) == -1) { |
IN_WRITE_END_NOTHROW |
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; |
IN_WRITE_END |
} |
void Inotify::RemoveAll() |
{ |
IN_WRITE_BEGIN |
IN_WP_MAP::iterator it = m_paths.begin(); |
while (it != m_paths.end()) { |
InotifyWatch* pW = (*it).second; |
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(); |
IN_WRITE_END |
} |
void Inotify::WaitForEvents(bool fNoIntr) throw (InotifyException) |
{ |
ssize_t len = 0; |
do { |
len = read(m_fd, m_buf, INOTIFY_BUFLEN); |
} while (fNoIntr && len == -1 && errno == EINTR); |
if (errno == EWOULDBLOCK) |
return; |
if (len < 0) |
throw InotifyException(IN_EXC_MSG("reading events failed"), errno, this); |
IN_WRITE_BEGIN |
ssize_t i = 0; |
while (i < len) { |
struct inotify_event* pEvt = (struct inotify_event*) &m_buf[i]; |
InotifyWatch* pW = FindWatch(pEvt->wd); |
if (pW != NULL) { |
InotifyEvent evt(pEvt, pW); |
m_events.push_back(evt); |
} |
i += INOTIFY_EVENT_SIZE + (ssize_t) pEvt->len; |
} |
IN_WRITE_END |
} |
bool Inotify::GetEvent(InotifyEvent* pEvt) throw (InotifyException) |
{ |
if (pEvt == NULL) |
throw InotifyException(IN_EXC_MSG("null pointer to event"), EINVAL, this); |
IN_WRITE_BEGIN |
bool b = !m_events.empty(); |
if (b) { |
*pEvt = m_events.front(); |
m_events.pop_front(); |
} |
IN_WRITE_END |
return b; |
} |
bool Inotify::PeekEvent(InotifyEvent* pEvt) throw (InotifyException) |
{ |
if (pEvt == NULL) |
throw InotifyException(IN_EXC_MSG("null pointer to event"), EINVAL, this); |
IN_READ_BEGIN |
bool b = !m_events.empty(); |
if (b) { |
*pEvt = m_events.front(); |
} |
IN_READ_END |
return b; |
} |
InotifyWatch* Inotify::FindWatch(int iDescriptor) |
{ |
IN_READ_BEGIN |
IN_WATCH_MAP::iterator it = m_watches.find(iDescriptor); |
InotifyWatch* pW = it == m_watches.end() ? NULL : (*it).second; |
IN_READ_END |
return pW; |
} |
InotifyWatch* Inotify::FindWatch(const std::string& rPath) |
{ |
IN_READ_BEGIN |
IN_WP_MAP::iterator it = m_paths.find(rPath); |
InotifyWatch* pW = it == m_paths.end() ? NULL : (*it).second; |
IN_READ_END |
return pW; |
} |
void Inotify::SetNonBlock(bool fNonBlock) throw (InotifyException) |
{ |
IN_WRITE_BEGIN |
if (m_fd == -1) { |
IN_WRITE_END_NOTHROW |
throw InotifyException(IN_EXC_MSG("invalid file descriptor"), EBUSY, this); |
} |
int res = fcntl(m_fd, F_GETFL); |
if (res == -1) { |
IN_WRITE_END_NOTHROW |
throw InotifyException(IN_EXC_MSG("cannot get inotify flags"), errno, this); |
} |
if (fNonBlock) { |
res |= O_NONBLOCK; |
} |
else { |
res &= ~O_NONBLOCK; |
} |
if (fcntl(m_fd, F_SETFL, res) == -1) { |
IN_WRITE_END_NOTHROW |
throw InotifyException(IN_EXC_MSG("cannot set inotify flags"), errno, this); |
} |
IN_WRITE_END |
} |
/incron/tags/incron-0.3.0/icd-main.cpp |
---|
0,0 → 1,231 |
/// inotify cron daemon main file |
/** |
* \file icd-main.cpp |
* |
* 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). |
* |
*/ |
#include <map> |
#include <signal.h> |
#include <wait.h> |
#include <pwd.h> |
#include <dirent.h> |
#include <syslog.h> |
#include <errno.h> |
#include <sys/poll.h> |
#include "inotify-cxx.h" |
#include "incron.h" |
#include "incrontab.h" |
#include "usertable.h" |
/// Daemon yes/no |
#define DAEMON true |
/// 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. |
* |
* \param[in] signo signal number |
*/ |
void on_signal(int signo) |
{ |
if (signo == SIGTERM || signo == SIGINT) |
g_fFinish = true; |
} |
/// Checks whether an user exists and has permission to use incron. |
/** |
* It searches for the given user name in the user database. |
* If it failes it returns 'false'. Otherwise it checks |
* permission files for this user (see InCronTab::CheckUser()). |
* |
* \param[in] user user name |
* \return true = user has permission to use incron, false = otherwise |
* |
* \sa InCronTab::CheckUser() |
*/ |
bool check_user(const char* user) |
{ |
struct passwd* pw = getpwnam(user); |
if (pw == NULL) |
return false; |
return InCronTab::CheckUser(user); |
} |
/// Attempts to load all user incron tables. |
/** |
* 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); |
} |
/// Main application function. |
/** |
* \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; |
} |
/incron/tags/incron-0.3.0/incrontab.h |
---|
0,0 → 1,220 |
/// inotify cron table manipulator classes header |
/** |
* \file incrontab.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 _INCRONTAB_H_ |
#define _INCRONTAB_H_ |
#include <string> |
#include <deque> |
#include "strtok.h" |
/// Incron table base directory |
#define INCRON_TABLE_BASE "/var/spool/incron/" |
/// Incron table entry class. |
class InCronTabEntry |
{ |
public: |
/// Constructor. |
/** |
* Creates an empty entry for later use with Parse(). |
* |
* \sa Parse() |
*/ |
InCronTabEntry(); |
/// Constructor. |
/** |
* Creates an entry based on defined parameters. |
* |
* \param[in] rPath watched filesystem path |
* \param[in] uMask event mask |
* \param[in] rCmd command string |
*/ |
InCronTabEntry(const std::string& rPath, uint32_t uMask, const std::string& rCmd); |
/// Destructor. |
~InCronTabEntry() {} |
/// Converts the entry to string representation. |
/** |
* This method creates a string for use in a table file. |
* |
* \return string representation |
*/ |
std::string ToString() const; |
/// Parses a string and attempts to extract entry parameters. |
/** |
* \param[in] rStr parsed string |
* \param[out] rEntry parametrized entry |
* \return true = success, false = failure |
*/ |
static bool Parse(const std::string& rStr, InCronTabEntry& rEntry); |
/// Returns the watch filesystem path. |
/** |
* \return watch path |
*/ |
inline const std::string& GetPath() const |
{ |
return m_path; |
} |
/// Returns the event mask. |
/** |
* \return event mask |
*/ |
inline int32_t GetMask() const |
{ |
return m_uMask; |
} |
/// Returns the command string. |
/** |
* \return command string |
*/ |
inline const std::string& GetCmd() const |
{ |
return m_cmd; |
} |
/// Checks whether this entry has set loop-avoidance. |
/** |
* \return true = no loop, false = loop allowed |
*/ |
inline bool IsNoLoop() const |
{ |
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 |
std::string m_cmd; ///< command string |
bool m_fNoLoop; ///< no loop yes/no |
}; |
/// Incron table class. |
class InCronTab |
{ |
public: |
/// Constructor. |
InCronTab() {} |
/// Destructor. |
~InCronTab() {} |
/// Add an entry to the table. |
/** |
* \param[in] rEntry table entry |
*/ |
inline void Add(const InCronTabEntry& rEntry) |
{ |
m_tab.push_back(rEntry); |
} |
/// Removes all entries. |
inline void Clear() |
{ |
m_tab.clear(); |
} |
/// Checks whether the table is empty. |
/** |
* \return true = empty, false = otherwise |
*/ |
inline bool IsEmpty() const |
{ |
return m_tab.empty(); |
} |
/// Returns the count of entries. |
/** |
* \return count of entries |
*/ |
inline int GetCount() const |
{ |
return (int) m_tab.size(); |
} |
/// Returns an entry. |
/** |
* \return reference to the entry for the given index |
* |
* \attention This method doesn't test index bounds. If you |
* pass an invalid value the program may crash |
* and/or behave unpredictible way! |
*/ |
inline InCronTabEntry& GetEntry(int index) |
{ |
return m_tab[index]; |
} |
/// Loads the table. |
/** |
* \param[in] rPath path to a source table file |
* \return true = success, false = failure |
*/ |
bool Load(const std::string& rPath); |
/// Saves the table. |
/** |
* \param[in] rPath path to a destination table file |
* \return true = success, false = failure |
*/ |
bool Save(const std::string& rPath); |
/// Checks whether an user has permission to use incron. |
/** |
* \param[in] rUser user name |
* \return true = permission OK, false = otherwise |
*/ |
static bool CheckUser(const std::string& rUser); |
/// Composes a path to an user incron table file. |
/** |
* \param[in] rUser user name |
* \return path to the table file |
* |
* \attention No tests (existence, permission etc.) are done. |
*/ |
static std::string GetUserTablePath(const std::string& rUser); |
protected: |
std::deque<InCronTabEntry> m_tab; ///< incron table |
}; |
#endif //_INCRONTAB_H_ |
/incron/tags/incron-0.3.0/TODO |
---|
0,0 → 1,4 |
Currently pending tasks: |
#0000101 - Temporary files not removed |
#0000103 - User overriding doesn't work |
/incron/tags/incron-0.3.0/strtok.cpp |
---|
0,0 → 1,140 |
/// string tokenizer implementation |
/** |
* \file strtok.cpp |
* |
* string tokenizer |
* |
* Copyright (C) 2006 Lukas Jelinek, <lukas@aiken.cz> |
* |
* This program is free software; you can redistribute it and/or |
* modify it under the terms of one of the following licenses: |
* |
* \li 1. X11-style license (see LICENSE-X11) |
* \li 2. GNU Lesser General Public License, version 2.1 (see LICENSE-LGPL) |
* \li 3. GNU General Public License, version 2 (see LICENSE-GPL) |
* |
* If you want to help with choosing the best license for you, |
* please visit http://www.gnu.org/licenses/license-list.html. |
* |
*/ |
#include <sstream> |
#include "strtok.h" |
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(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) { |
rToken = m_str.substr(m_pos, i - m_pos); |
m_pos = i + 1; |
return; |
} |
} |
rToken = m_str.substr(m_pos); |
m_pos = m_len; |
} |
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/tags/incron-0.3.0/inotify-cxx.h |
---|
0,0 → 1,737 |
/// inotify C++ interface header |
/** |
* \file inotify-cxx.h |
* |
* inotify C++ interface |
* |
* Copyright (C) 2006 Lukas Jelinek, <lukas@aiken.cz> |
* |
* This program is free software; you can redistribute it and/or |
* modify it under the terms of one of the following licenses: |
* |
* \li 1. X11-style license (see LICENSE-X11) |
* \li 2. GNU Lesser General Public License, version 2.1 (see LICENSE-LGPL) |
* \li 3. GNU General Public License, version 2 (see LICENSE-GPL) |
* |
* If you want to help with choosing the best license for you, |
* please visit http://www.gnu.org/licenses/license-list.html. |
* |
*/ |
#ifndef _INOTIFYCXX_H_ |
#define _INOTIFYCXX_H_ |
#include <string> |
#include <deque> |
#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 |
#ifndef __NR_inotify_init |
#include <sys/inotify-syscalls.h> |
#endif // __NR_inotify_init |
/// Event struct size |
#define INOTIFY_EVENT_SIZE (sizeof(struct inotify_event)) |
/// Event buffer length |
#define INOTIFY_BUFLEN (1024 * (INOTIFY_EVENT_SIZE + 16)) |
/// Helper macro for creating exception messages. |
/** |
* It prepends the message by the function name. |
*/ |
#define IN_EXC_MSG(msg) (std::string(__PRETTY_FUNCTION__) + ": " + msg) |
/// inotify-cxx thread safety |
/** |
* If this symbol is defined you can use this interface safely |
* threaded applications. Remember that it slightly degrades |
* performance. |
* |
* Even if INOTIFY_THREAD_SAFE is defined some classes stay |
* unsafe. If you must use them (must you?) in more than one |
* thread concurrently you need to implement explicite locking. |
* |
* You need not to define INOTIFY_THREAD_SAFE in that cases |
* where the application is multithreaded but all the inotify |
* infrastructure will be managed only in one thread. This is |
* the recommended way. |
* |
* Locking may fail (it is very rare but not impossible). In this |
* case an exception is thrown. But if unlocking fails in case |
* of an error it does nothing (this failure is ignored). |
*/ |
#ifdef INOTIFY_THREAD_SAFE |
#include <pthread.h> |
#define IN_LOCK_DECL mutable pthread_rwlock_t __m_lock; |
#define IN_LOCK_INIT \ |
{ \ |
pthread_rwlockattr_t attr; \ |
int res = 0; \ |
if ((res = pthread_rwlockattr_init(&attr)) != 0) \ |
throw InotifyException(IN_EXC_MSG("cannot initialize lock attributes"), res, this); \ |
if ((res = pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP)) != 0) \ |
throw InotifyException(IN_EXC_MSG("cannot set lock kind"), res, this); \ |
if ((res = pthread_rwlock_init(&__m_lock, &attr)) != 0) \ |
throw InotifyException(IN_EXC_MSG("cannot initialize lock"), res, this); \ |
pthread_rwlockattr_destroy(&attr); \ |
} |
#define IN_LOCK_DONE pthread_rwlock_destroy(&__m_lock); |
#define IN_READ_BEGIN \ |
{ \ |
int res = pthread_rwlock_rdlock(&__m_lock); \ |
if (res != 0) \ |
throw InotifyException(IN_EXC_MSG("locking for reading failed"), res, (void*) this); \ |
} |
#define IN_READ_END \ |
{ \ |
int res = pthread_rwlock_unlock(&__m_lock); \ |
if (res != 0) \ |
throw InotifyException(IN_EXC_MSG("unlocking failed"), res, (void*) this); \ |
} |
#define IN_READ_END_NOTHROW pthread_rwlock_unlock(&__m_lock); |
#define IN_WRITE_BEGIN \ |
{ \ |
int res = pthread_rwlock_wrlock(&__m_lock); \ |
if (res != 0) \ |
throw InotifyException(IN_EXC_MSG("locking for writing failed"), res, (void*) this); \ |
} |
#define IN_WRITE_END IN_READ_END |
#define IN_WRITE_END_NOTHROW IN_READ_END_NOTHROW |
#else // INOTIFY_THREAD_SAFE |
#define IN_LOCK_DECL |
#define IN_LOCK_INIT |
#define IN_LOCK_DONE |
#define IN_READ_BEGIN |
#define IN_READ_END |
#define IN_READ_END_NOTHROW |
#define IN_WRITE_BEGIN |
#define IN_WRITE_END |
#define IN_WRITE_END_NOTHROW |
#endif // INOTIFY_THREAD_SAFE |
// forward declaration |
class InotifyWatch; |
class Inotify; |
/// Class for inotify exceptions |
/** |
* This class allows to acquire information about exceptional |
* events. It makes easier to log or display error messages |
* and to identify problematic code locations. |
* |
* Although this class is basically thread-safe it is not intended |
* to be shared between threads. |
*/ |
class InotifyException |
{ |
public: |
/// Constructor |
/** |
* \param[in] rMsg message |
* \param[in] iErr error number (see errno.h) |
* \param[in] pSrc source |
*/ |
InotifyException(const std::string& rMsg = "", int iErr = 0, void* pSrc = NULL) |
: m_msg(rMsg), |
m_err(iErr) |
{ |
m_pSrc = pSrc; |
} |
/// Returns the exception message. |
/** |
* \return message |
*/ |
inline const std::string& GetMessage() const |
{ |
return m_msg; |
} |
/// Returns the exception error number. |
/** |
* If not applicable this value is 0 (zero). |
* |
* \return error number (standardized; see errno.h) |
*/ |
inline int GetErrorNumber() const |
{ |
return m_err; |
} |
/// Returns the exception source. |
/** |
* \return source |
*/ |
inline void* GetSource() const |
{ |
return m_pSrc; |
} |
protected: |
std::string m_msg; ///< message |
int m_err; ///< error number |
mutable void* m_pSrc; ///< source |
}; |
/// inotify event class |
/** |
* It holds all information about inotify event and provides |
* access to its particular values. |
* |
* This class is not (and is not intended to be) thread-safe |
* and therefore it must not be used concurrently in multiple |
* threads. |
*/ |
class InotifyEvent |
{ |
public: |
/// Constructor. |
/** |
* Creates a plain event. |
*/ |
InotifyEvent() |
: m_uMask(0), |
m_uCookie(0) |
{ |
m_pWatch = NULL; |
} |
/// Constructor. |
/** |
* Creates an event based on inotify event data. |
* For NULL pointers it works the same way as InotifyEvent(). |
* |
* \param[in] pEvt event data |
* \param[in] pWatch inotify watch |
*/ |
InotifyEvent(const struct inotify_event* pEvt, InotifyWatch* pWatch) |
: m_uMask(0), |
m_uCookie(0) |
{ |
if (pEvt != NULL) { |
m_uMask = (uint32_t) pEvt->mask; |
m_uCookie = (uint32_t) pEvt->cookie; |
if (pEvt->name != NULL) |
m_name = pEvt->name; |
m_pWatch = pWatch; |
} |
else { |
m_pWatch = NULL; |
} |
} |
/// Destructor. |
~InotifyEvent() {} |
/// Returns the event watch descriptor. |
/** |
* \return watch descriptor |
* |
* \sa InotifyWatch::GetDescriptor() |
*/ |
int32_t GetDescriptor() const; |
/// Returns the event mask. |
/** |
* \return event mask |
* |
* \sa InotifyWatch::GetMask() |
*/ |
inline uint32_t GetMask() const |
{ |
return m_uMask; |
} |
/// Checks a value for the event type. |
/** |
* \param[in] uValue checked value |
* \param[in] uType type which is checked for |
* \return true = the value contains the given type, false = otherwise |
*/ |
inline static bool IsType(uint32_t uValue, uint32_t uType) |
{ |
return ((uValue & uType) != 0) && ((~uValue & uType) == 0); |
} |
/// Checks for the event type. |
/** |
* \param[in] uType type which is checked for |
* \return true = event mask contains the given type, false = otherwise |
*/ |
inline bool IsType(uint32_t uType) const |
{ |
return IsType(m_uMask, uType); |
} |
/// Returns the event cookie. |
/** |
* \return event cookie |
*/ |
inline uint32_t GetCookie() const |
{ |
return m_uCookie; |
} |
/// Returns the event name length. |
/** |
* \return event name length |
*/ |
inline uint32_t GetLength() const |
{ |
return (uint32_t) m_name.length(); |
} |
/// Returns the event name. |
/** |
* \return event name |
*/ |
inline const std::string& GetName() const |
{ |
return m_name; |
} |
/// Extracts the event name. |
/** |
* \param[out] rName event name |
*/ |
inline void GetName(std::string& rName) const |
{ |
rName = GetName(); |
} |
/// Returns the source watch. |
/** |
* \return source watch |
*/ |
inline InotifyWatch* GetWatch() |
{ |
return m_pWatch; |
} |
/// Finds the appropriate mask for a name. |
/** |
* \param[in] rName mask name |
* \return mask for name; 0 on failure |
*/ |
static uint32_t GetMaskByName(const std::string& rName); |
/// Fills the string with all types contained in an event mask value. |
/** |
* \param[in] uValue event mask value |
* \param[out] rStr dumped event types |
*/ |
static void DumpTypes(uint32_t uValue, std::string& rStr); |
/// Fills the string with all types contained in the event mask. |
/** |
* \param[out] rStr dumped event types |
*/ |
void DumpTypes(std::string& rStr) const; |
private: |
uint32_t m_uMask; ///< mask |
uint32_t m_uCookie; ///< cookie |
std::string m_name; ///< name |
InotifyWatch* m_pWatch; ///< source watch |
}; |
/// inotify watch class |
/** |
* It holds information about the inotify watch on a particular |
* inode. |
* |
* If the INOTIFY_THREAD_SAFE is defined this class is thread-safe. |
*/ |
class InotifyWatch |
{ |
public: |
/// Constructor. |
/** |
* Creates an inotify watch. Because this watch is |
* inactive it has an invalid descriptor (-1). |
* |
* \param[in] rPath watched file path |
* \param[in] uMask mask for events |
* \param[in] fEnabled events enabled yes/no |
*/ |
InotifyWatch(const std::string& rPath, int32_t uMask, bool fEnabled = true) |
: m_path(rPath), |
m_uMask(uMask), |
m_wd((int32_t) -1), |
m_fEnabled(fEnabled) |
{ |
IN_LOCK_INIT |
} |
/// Destructor. |
~InotifyWatch() |
{ |
IN_LOCK_DONE |
} |
/// Returns the watch descriptor. |
/** |
* \return watch descriptor; -1 for inactive watch |
*/ |
inline int32_t GetDescriptor() const |
{ |
return m_wd; |
} |
/// Returns the watched file path. |
/** |
* \return file path |
*/ |
inline const std::string& GetPath() const |
{ |
return m_path; |
} |
/// Returns the watch event mask. |
/** |
* \return event mask |
*/ |
inline uint32_t GetMask() const |
{ |
return (uint32_t) m_uMask; |
} |
/// Sets the watch event mask. |
/** |
* If the watch is active (added to an instance of Inotify) |
* 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 |
*/ |
inline Inotify* GetInotify() |
{ |
return m_pInotify; |
} |
/// Enables/disables the watch. |
/** |
* If the watch is active (added to an instance of Inotify) |
* 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; |
} |
private: |
friend class Inotify; |
std::string m_path; ///< watched file path |
uint32_t m_uMask; ///< event mask |
int32_t m_wd; ///< watch descriptor |
Inotify* m_pInotify; ///< inotify object |
bool m_fEnabled; ///< events enabled yes/no |
IN_LOCK_DECL |
}; |
/// 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 |
/** |
* It holds information about the inotify device descriptor |
* and manages the event queue. |
* |
* If the INOTIFY_THREAD_SAFE is defined this class is thread-safe. |
*/ |
class Inotify |
{ |
public: |
/// Constructor. |
/** |
* Creates and initializes an instance of inotify communication |
* object (opens the inotify device). |
* |
* \throw InotifyException thrown if inotify isn't available |
*/ |
Inotify() throw (InotifyException); |
/// Destructor. |
/** |
* Calls Close() due to clean-up. |
*/ |
~Inotify(); |
/// Removes all watches and closes the inotify device. |
void Close(); |
/// Adds a new watch. |
/** |
* \param[in] pWatch inotify watch |
* |
* \throw InotifyException thrown if adding failed |
*/ |
void Add(InotifyWatch* pWatch) throw (InotifyException); |
/// Adds a new watch. |
/** |
* \param[in] rWatch inotify watch |
* |
* \throw InotifyException thrown if adding failed |
*/ |
inline void Add(InotifyWatch& rWatch) throw (InotifyException) |
{ |
Add(&rWatch); |
} |
/// Removes a watch. |
/** |
* If the given watch is not present it does nothing. |
* |
* \param[in] pWatch inotify watch |
* |
* \throw InotifyException thrown if removing failed |
*/ |
void Remove(InotifyWatch* pWatch) throw (InotifyException); |
/// Removes a watch. |
/** |
* If the given watch is not present it does nothing. |
* |
* \param[in] rWatch inotify watch |
* |
* \throw InotifyException thrown if removing failed |
*/ |
inline void Remove(InotifyWatch& rWatch) throw (InotifyException) |
{ |
Remove(&rWatch); |
} |
/// Removes all watches. |
void RemoveAll(); |
/// Returns the count of watches. |
/** |
* This is the total count of all watches (regardless whether |
* enabled or not). |
* |
* \return count of watches |
* |
* \sa GetEnabledCount() |
*/ |
inline size_t GetWatchCount() const |
{ |
IN_READ_BEGIN |
size_t n = (size_t) m_paths.size(); |
IN_READ_END |
return n; |
} |
/// Returns the count of enabled watches. |
/** |
* \return count of enabled watches |
* |
* \sa GetWatchCount() |
*/ |
inline size_t GetEnabledCount() const |
{ |
IN_READ_BEGIN |
size_t n = (size_t) m_watches.size(); |
IN_READ_END |
return n; |
} |
/// Waits for inotify events. |
/** |
* It waits until one or more events occur. When called |
* in nonblocking mode it only retrieves occurred events |
* to the internal queue and exits. |
* |
* \param[in] fNoIntr if true it re-calls the system call after a handled signal |
* |
* \throw InotifyException thrown if reading events failed |
* |
* \sa SetNonBlock() |
*/ |
void WaitForEvents(bool fNoIntr = false) throw (InotifyException); |
/// Returns the count of received and queued events. |
/** |
* This number is related to the events in the queue inside |
* this object, not to the events pending in the kernel. |
* |
* \return count of events |
*/ |
inline size_t GetEventCount() |
{ |
IN_READ_BEGIN |
size_t n = (size_t) m_events.size(); |
IN_READ_END |
return n; |
} |
/// Extracts a queued inotify event. |
/** |
* The extracted event is removed from the queue. |
* If the pointer is NULL it does nothing. |
* |
* \param[in,out] pEvt event object |
* |
* \throw InotifyException thrown if the provided pointer is NULL |
*/ |
bool GetEvent(InotifyEvent* pEvt) throw (InotifyException); |
/// Extracts a queued inotify event. |
/** |
* The extracted event is removed from the queue. |
* |
* \param[in,out] rEvt event object |
* |
* \throw InotifyException thrown only in very anomalous cases |
*/ |
bool GetEvent(InotifyEvent& rEvt) throw (InotifyException) |
{ |
return GetEvent(&rEvt); |
} |
/// Extracts a queued inotify event (without removing). |
/** |
* The extracted event stays in the queue. |
* If the pointer is NULL it does nothing. |
* |
* \param[in,out] pEvt event object |
* |
* \throw InotifyException thrown if the provided pointer is NULL |
*/ |
bool PeekEvent(InotifyEvent* pEvt) throw (InotifyException); |
/// Extracts a queued inotify event (without removing). |
/** |
* The extracted event stays in the queue. |
* |
* \param[in,out] rEvt event object |
* |
* \throw InotifyException thrown only in very anomalous cases |
*/ |
bool PeekEvent(InotifyEvent& rEvt) throw (InotifyException) |
{ |
return PeekEvent(&rEvt); |
} |
/// Searches for a watch by a watch descriptor. |
/** |
* It tries to find a watch by the given descriptor. |
* |
* \param[in] iDescriptor watch descriptor |
* \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 |
* functions (poll(), select(), fcntl() etc.). |
* |
* \return valid file descriptor or -1 for inactive object |
* |
* \sa SetNonBlock() |
*/ |
inline int GetDescriptor() const |
{ |
return m_fd; |
} |
/// Enables/disables non-blocking mode. |
/** |
* Use this mode if you want to monitor the descriptor |
* (acquired thru GetDescriptor()) in functions such as |
* poll(), select() etc. |
* |
* \param[in] fNonBlock enable/disable non-blocking mode |
* |
* \throw InotifyException thrown if setting mode failed |
* |
* \sa GetDescriptor() |
*/ |
void SetNonBlock(bool fNonBlock) throw (InotifyException); |
private: |
int m_fd; ///< file descriptor |
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 |
IN_LOCK_DECL |
friend class InotifyWatch; |
}; |
#endif //_INOTIFYCXX_H_ |
/incron/tags/incron-0.3.0/usertable.cpp |
---|
0,0 → 1,305 |
/// inotify cron daemon user tables implementation |
/** |
* \file usertable.cpp |
* |
* 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). |
* |
*/ |
#include <pwd.h> |
#include <syslog.h> |
#include <errno.h> |
#include <sys/wait.h> |
#include "usertable.h" |
PROC_LIST UserTable::s_procList; |
void on_proc_done(InotifyWatch* pW) |
{ |
pW->SetEnabled(true); |
} |
EventDispatcher::EventDispatcher(Inotify* pIn) |
{ |
m_pIn = pIn; |
} |
void EventDispatcher::DispatchEvent(InotifyEvent& rEvt) |
{ |
if (m_pIn == NULL) |
return; |
InotifyWatch* pW = rEvt.GetWatch(); |
if (pW == NULL) |
return; |
UserTable* pT = FindTable(pW); |
if (pT == NULL) |
return; |
pT->OnEvent(rEvt); |
} |
void EventDispatcher::Register(InotifyWatch* pWatch, UserTable* pTab) |
{ |
if (pWatch != NULL && pTab != NULL) |
m_maps.insert(IWUT_MAP::value_type(pWatch, pTab)); |
} |
void EventDispatcher::Unregister(InotifyWatch* pWatch) |
{ |
IWUT_MAP::iterator it = m_maps.find(pWatch); |
if (it == m_maps.end()) |
m_maps.erase(it); |
} |
void EventDispatcher::UnregisterAll(UserTable* pTab) |
{ |
IWUT_MAP::iterator it = m_maps.begin(); |
while (it != m_maps.end()) { |
if ((*it).second == pTab) { |
IWUT_MAP::iterator it2 = it; |
it++; |
m_maps.erase(it2); |
} |
else { |
it++; |
} |
} |
} |
UserTable* EventDispatcher::FindTable(InotifyWatch* pW) |
{ |
IWUT_MAP::iterator it = m_maps.find(pW); |
if (it == m_maps.end()) |
return NULL; |
return (*it).second; |
} |
UserTable::UserTable(Inotify* pIn, EventDispatcher* pEd, const std::string& rUser) |
: m_user(rUser) |
{ |
m_pIn = pIn; |
m_pEd = pEd; |
} |
UserTable::~UserTable() |
{ |
Dispose(); |
} |
void UserTable::Load() |
{ |
m_tab.Load(InCronTab::GetUserTablePath(m_user)); |
int cnt = m_tab.GetCount(); |
for (int i=0; i<cnt; i++) { |
InCronTabEntry& rE = m_tab.GetEntry(i); |
InotifyWatch* pW = new InotifyWatch(rE.GetPath(), rE.GetMask()); |
try { |
m_pIn->Add(pW); |
m_pEd->Register(pW, this); |
m_map.insert(IWCE_MAP::value_type(pW, &rE)); |
} catch (InotifyException e) { |
syslog(LOG_ERR, "cannot create watch for user %s", m_user.c_str()); |
delete pW; |
} |
} |
} |
void UserTable::Dispose() |
{ |
IWCE_MAP::iterator it = m_map.begin(); |
while (it != m_map.end()) { |
InotifyWatch* pW = (*it).first; |
m_pEd->Unregister(pW); |
m_pIn->Remove(pW); |
delete pW; |
it++; |
} |
m_map.clear(); |
} |
void UserTable::OnEvent(InotifyEvent& rEvt) |
{ |
InotifyWatch* pW = rEvt.GetWatch(); |
InCronTabEntry* pE = FindEntry(pW); |
if (pE == NULL) |
return; |
std::string cmd; |
const std::string& cs = pE->GetCmd(); |
size_t pos = 0; |
size_t oldpos = 0; |
size_t len = cs.length(); |
while ((pos = cs.find('$', oldpos)) != std::string::npos) { |
if (pos < len - 1) { |
size_t px = pos + 1; |
if (cs[px] == '$') { |
cmd.append(cs.substr(oldpos, pos-oldpos+1)); |
oldpos = pos + 2; |
} |
else { |
cmd.append(cs.substr(oldpos, pos-oldpos)); |
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 { |
cmd.append(cs.substr(oldpos, pos-oldpos)); |
oldpos = pos + 1; |
} |
} |
cmd.append(cs.substr(oldpos)); |
int argc; |
char** argv; |
if (!PrepareArgs(cmd, argc, argv)) { |
syslog(LOG_ERR, "cannot prepare command arguments"); |
return; |
} |
syslog(LOG_INFO, "(%s) CMD (%s)", m_user.c_str(), cmd.c_str()); |
if (pE->IsNoLoop()) |
pW->SetEnabled(false); |
ProcData_t pd; |
pd.pid = fork(); |
if (pd.pid == 0) { |
struct passwd* pwd = getpwnam(m_user.c_str()); |
if ( pwd == NULL // user not found |
|| setuid(pwd->pw_uid) != 0 // setting UID failed |
|| execvp(argv[0], argv) != 0) // exec failed |
{ |
_exit(1); |
} |
} |
else if (pd.pid > 0) { |
if (pE->IsNoLoop()) { |
pd.onDone = on_proc_done; |
pd.pWatch = pW; |
} |
else { |
pd.onDone = NULL; |
pd.pWatch = NULL; |
} |
s_procList.push_back(pd); |
} |
else { |
if (pE->IsNoLoop()) |
pW->SetEnabled(true); |
syslog(LOG_ERR, "cannot fork process: %s", strerror(errno)); |
} |
CleanupArgs(argc, argv); |
} |
InCronTabEntry* UserTable::FindEntry(InotifyWatch* pWatch) |
{ |
IWCE_MAP::iterator it = m_map.find(pWatch); |
if (it == m_map.end()) |
return NULL; |
return (*it).second; |
} |
bool UserTable::PrepareArgs(const std::string& rCmd, int& argc, char**& argv) |
{ |
if (rCmd.empty()) |
return false; |
StringTokenizer tok(rCmd, ' ', '\\'); |
std::deque<std::string> args; |
while (tok.HasMoreTokens()) { |
args.push_back(tok.GetNextToken()); |
} |
if (args.empty()) |
return false; |
argc = (int) args.size(); |
argv = new char*[argc+1]; |
argv[argc] = NULL; |
for (int i=0; i<argc; i++) { |
const std::string& s = args[i]; |
size_t len = s.length(); |
argv[i] = new char[len+1]; |
strcpy(argv[i], s.c_str()); |
} |
return true; |
} |
void UserTable::CleanupArgs(int argc, char** argv) |
{ |
for (int i=0; i<argc; i++) { |
delete[] argv[i]; |
} |
delete[] argv; |
} |
void UserTable::FinishDone() |
{ |
PROC_LIST::iterator it = s_procList.begin(); |
while (it != s_procList.end()) { |
ProcData_t& pd = *it; |
int status = 0; |
int res = waitpid(pd.pid, &status, WNOHANG); |
if (res == pd.pid && (WIFEXITED(status) || WIFSIGNALED(status))) { |
if (pd.onDone != NULL) |
(*pd.onDone)(pd.pWatch); |
it = s_procList.erase(it); |
} |
else { |
it++; |
} |
} |
} |
/incron/tags/incron-0.3.0/strtok.h |
---|
0,0 → 1,231 |
/// string tokenizer header |
/** |
* \file strtok.h |
* |
* string tokenizer |
* |
* Copyright (C) 2006 Lukas Jelinek, <lukas@aiken.cz> |
* |
* This program is free software; you can redistribute it and/or |
* modify it under the terms of one of the following licenses: |
* |
* \li 1. X11-style license (see LICENSE-X11) |
* \li 2. GNU Lesser General Public License, version 2.1 (see LICENSE-LGPL) |
* \li 3. GNU General Public License, version 2 (see LICENSE-GPL) |
* |
* If you want to help with choosing the best license for you, |
* please visit http://www.gnu.org/licenses/license-list.html. |
* |
*/ |
#ifndef _STRTOK_H_ |
#define _STRTOK_H_ |
#include <string> |
typedef std::string::size_type SIZE; |
/// Simple string tokenizer class. |
/** |
* This class implements a string tokenizer. It splits a string |
* by a character to a number of elements (tokens) which are |
* provided sequentially. |
* |
* 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 |
{ |
public: |
/// Constructor. |
/** |
* Creates a ready-to-use tokenizer. |
* |
* \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 = ',', char cPrefix = '\0'); |
/// Destructor. |
~StringTokenizer() {} |
/// Checks whether the tokenizer can provide more tokens. |
/** |
* \return true = more tokens available, false = otherwise |
*/ |
inline bool HasMoreTokens() const |
{ |
return m_pos < m_len; |
} |
/// 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(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) |
{ |
m_cDelim = cDelim; |
} |
/// Returns the delimiter (separator) character. |
/** |
* \return delimiter character |
*/ |
inline char GetDelimiter() const |
{ |
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. |
*/ |
inline void Reset() |
{ |
m_pos = 0; |
} |
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); |
}; |
#endif //_STRTOK_H_ |
/incron/tags/incron-0.3.0/Makefile |
---|
0,0 → 1,65 |
PREFIX = /usr/local |
DATADIR = /var/spool/incron |
USER = incron |
CXX = g++ |
INSTALL = install |
OPTIMIZE = -O2 |
DEBUG = -g0 |
WARNINGS = -Wall |
CPPFLAGS = |
CXXFLAGS = $(OPTIMIZE) $(DEBUG) $(WARNINGS) |
LDFLAGS = $(WARNINGS) |
PROGRAMS = incrond incrontab |
INCROND_OBJ = icd-main.o incrontab.o inotify-cxx.o usertable.o strtok.o |
INCRONTAB_OBJ = ict-main.o incrontab.o inotify-cxx.o strtok.o |
all: $(PROGRAMS) |
incrond: $(INCROND_OBJ) |
$(CXX) $(LDFLAGS) -o $@ $(INCROND_OBJ) |
incrontab: $(INCRONTAB_OBJ) |
$(CXX) $(LDFLAGS) -o $@ $(INCRONTAB_OBJ) |
.cpp.o: |
$(CXX) -c $(CPPFLAGS) $(CXXFLAGS) -o $@ $< |
clean: |
rm -f $(PROGRAMS) |
rm -f *.o |
distclean: clean |
install: all |
[ -d $(PREFIX) ] |
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) |
uninstall: |
[ -d $(PREFIX) ] |
rm -f $(PREFIX)/bin/incrontab |
rm -f $(PREFIX)/sbin/incrond |
userdel $(USER) |
.PHONY: all clean distclean install uninstall |
.POSIX: |
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 incron.h |
strtok.o: strtok.cpp strtok.h |
/incron/tags/incron-0.3.0/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_ |
/incron/tags/incron-0.3.0/LICENSE-X11 |
---|
0,0 → 1,22 |
Copyright (c) 2006 Lukas Jelinek |
Permission is hereby granted, free of charge, to any person |
obtaining a copy of this software and associated documentation |
files (the "Software"), to deal in the Software without |
restriction, including without limitation the rights to use, |
copy, modify, merge, publish, distribute, sublicense, and/or sell |
copies of the Software, and to permit persons to whom the |
Software is furnished to do so, subject to the following |
conditions: |
The above copyright notice and this permission notice shall be |
included in all copies or substantial portions of the Software. |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES |
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
OTHER DEALINGS IN THE SOFTWARE. |
/incron/tags/incron-0.3.0/usertable.h |
---|
0,0 → 1,183 |
/// inotify cron daemon user tables header |
/** |
* \file usertable.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 _USERTABLE_H_ |
#define _USERTABLE_H_ |
#include <map> |
#include <deque> |
#include "inotify-cxx.h" |
#include "incrontab.h" |
class UserTable; |
/// Callback for calling after a process finishes. |
typedef void (*proc_done_cb)(InotifyWatch*); |
/// Child process data |
typedef struct |
{ |
pid_t pid; ///< PID |
proc_done_cb onDone; ///< function called after process finishes |
InotifyWatch* pWatch; ///< related watch |
} ProcData_t; |
/// Watch-to-usertable mapping |
typedef std::map<InotifyWatch*, UserTable*> IWUT_MAP; |
/// Watch-to-tableentry mapping |
typedef std::map<InotifyWatch*, InCronTabEntry*> IWCE_MAP; |
/// Child process list |
typedef std::deque<ProcData_t> PROC_LIST; |
/// Event dispatcher class. |
/** |
* This class distributes inotify events to appropriate user tables. |
*/ |
class EventDispatcher |
{ |
public: |
/// Constructor. |
/** |
* \param[in] pIn inotify object |
*/ |
EventDispatcher(Inotify* pIn); |
/// Destructor. |
~EventDispatcher() {} |
/// Dispatches an event. |
/** |
* \param[in] rEvt inotify event |
*/ |
void DispatchEvent(InotifyEvent& rEvt); |
/// Registers a watch for an user table. |
/** |
* \param[in] pWatch inotify watch |
* \param[in] pTab user table |
*/ |
void Register(InotifyWatch* pWatch, UserTable* pTab); |
/// Unregisters a watch. |
/** |
* \param[in] pWatch inotify watch |
*/ |
void Unregister(InotifyWatch* pWatch); |
/// Unregisters all watches for an user table. |
/** |
* \param[in] pTab user table |
*/ |
void UnregisterAll(UserTable* pTab); |
private: |
Inotify* m_pIn; ///< inotify object |
IWUT_MAP m_maps; ///< watch-to-usertable mapping |
/// Finds an user table for a watch. |
/** |
* \param[in] pW inotify watch |
* \return pointer to the appropriate watch; NULL if no such watch exists |
*/ |
UserTable* FindTable(InotifyWatch* pW); |
}; |
/// User table class. |
/** |
* This class processes inotify events for an user. It creates |
* child processes which do appropriate actions as defined |
* in the user table file. |
*/ |
class UserTable |
{ |
public: |
/// Constructor. |
/** |
* \param[in] pIn inotify object |
* \param[in] pEd event dispatcher |
* \param[in] rUser user name |
*/ |
UserTable(Inotify* pIn, EventDispatcher* pEd, const std::string& rUser); |
/// Destructor. |
virtual ~UserTable(); |
/// Loads the table. |
/** |
* All loaded entries have their inotify watches and are |
* registered for event dispatching. |
* If loading fails the table remains empty. |
*/ |
void Load(); |
/// Removes all entries from the table. |
/** |
* All entries are unregistered from the event dispatcher and |
* their watches are destroyed. |
*/ |
void Dispose(); |
/// Processes an inotify event. |
/** |
* \param[in] rEvt inotify event |
*/ |
void OnEvent(InotifyEvent& rEvt); |
/// Cleans-up all zombie child processes and enables disabled watches. |
/** |
* \attention This method must be called AFTER processing all events |
* which has been caused by the processes. |
*/ |
static void FinishDone(); |
private: |
Inotify* m_pIn; ///< inotify object |
EventDispatcher* m_pEd; ///< event dispatcher |
std::string m_user; ///< user name |
InCronTab m_tab; ///< incron table |
IWCE_MAP m_map; ///< watch-to-entry mapping |
static PROC_LIST s_procList; ///< child process list |
/// Finds an entry for a watch. |
/** |
* \param[in] pWatch inotify watch |
* \return pointer to the appropriate entry; NULL if no such entry exists |
*/ |
InCronTabEntry* FindEntry(InotifyWatch* pWatch); |
/// Prepares arguments for creating a child process. |
/** |
* \param[in] rCmd command string |
* \param[out] argc argument count |
* \param[out] argv argument array |
* \return true = success, false = failure |
*/ |
bool PrepareArgs(const std::string& rCmd, int& argc, char**& argv); |
/// Frees memory allocated for arguments. |
/** |
* \param[in] argc argument count |
* \param[in] argv argument array |
*/ |
void CleanupArgs(int argc, char** argv); |
}; |
#endif //_USERTABLE_H_ |
/incron/tags/incron-0.3.0/LICENSE-GPL |
---|
0,0 → 1,339 |
GNU GENERAL PUBLIC LICENSE |
Version 2, June 1991 |
Copyright (C) 1989, 1991 Free Software Foundation, Inc. |
675 Mass Ave, Cambridge, MA 02139, USA |
Everyone is permitted to copy and distribute verbatim copies |
of this license document, but changing it is not allowed. |
Preamble |
The licenses for most software are designed to take away your |
freedom to share and change it. By contrast, the GNU General Public |
License is intended to guarantee your freedom to share and change free |
software--to make sure the software is free for all its users. This |
General Public License applies to most of the Free Software |
Foundation's software and to any other program whose authors commit to |
using it. (Some other Free Software Foundation software is covered by |
the GNU Library General Public License instead.) You can apply it to |
your programs, too. |
When we speak of free software, we are referring to freedom, not |
price. Our General Public Licenses are designed to make sure that you |
have the freedom to distribute copies of free software (and charge for |
this service if you wish), that you receive source code or can get it |
if you want it, that you can change the software or use pieces of it |
in new free programs; and that you know you can do these things. |
To protect your rights, we need to make restrictions that forbid |
anyone to deny you these rights or to ask you to surrender the rights. |
These restrictions translate to certain responsibilities for you if you |
distribute copies of the software, or if you modify it. |
For example, if you distribute copies of such a program, whether |
gratis or for a fee, you must give the recipients all the rights that |
you have. You must make sure that they, too, receive or can get the |
source code. And you must show them these terms so they know their |
rights. |
We protect your rights with two steps: (1) copyright the software, and |
(2) offer you this license which gives you legal permission to copy, |
distribute and/or modify the software. |
Also, for each author's protection and ours, we want to make certain |
that everyone understands that there is no warranty for this free |
software. If the software is modified by someone else and passed on, we |
want its recipients to know that what they have is not the original, so |
that any problems introduced by others will not reflect on the original |
authors' reputations. |
Finally, any free program is threatened constantly by software |
patents. We wish to avoid the danger that redistributors of a free |
program will individually obtain patent licenses, in effect making the |
program proprietary. To prevent this, we have made it clear that any |
patent must be licensed for everyone's free use or not licensed at all. |
The precise terms and conditions for copying, distribution and |
modification follow. |
GNU GENERAL PUBLIC LICENSE |
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION |
0. This License applies to any program or other work which contains |
a notice placed by the copyright holder saying it may be distributed |
under the terms of this General Public License. The "Program", below, |
refers to any such program or work, and a "work based on the Program" |
means either the Program or any derivative work under copyright law: |
that is to say, a work containing the Program or a portion of it, |
either verbatim or with modifications and/or translated into another |
language. (Hereinafter, translation is included without limitation in |
the term "modification".) Each licensee is addressed as "you". |
Activities other than copying, distribution and modification are not |
covered by this License; they are outside its scope. The act of |
running the Program is not restricted, and the output from the Program |
is covered only if its contents constitute a work based on the |
Program (independent of having been made by running the Program). |
Whether that is true depends on what the Program does. |
1. You may copy and distribute verbatim copies of the Program's |
source code as you receive it, in any medium, provided that you |
conspicuously and appropriately publish on each copy an appropriate |
copyright notice and disclaimer of warranty; keep intact all the |
notices that refer to this License and to the absence of any warranty; |
and give any other recipients of the Program a copy of this License |
along with the Program. |
You may charge a fee for the physical act of transferring a copy, and |
you may at your option offer warranty protection in exchange for a fee. |
2. You may modify your copy or copies of the Program or any portion |
of it, thus forming a work based on the Program, and copy and |
distribute such modifications or work under the terms of Section 1 |
above, provided that you also meet all of these conditions: |
a) You must cause the modified files to carry prominent notices |
stating that you changed the files and the date of any change. |
b) You must cause any work that you distribute or publish, that in |
whole or in part contains or is derived from the Program or any |
part thereof, to be licensed as a whole at no charge to all third |
parties under the terms of this License. |
c) If the modified program normally reads commands interactively |
when run, you must cause it, when started running for such |
interactive use in the most ordinary way, to print or display an |
announcement including an appropriate copyright notice and a |
notice that there is no warranty (or else, saying that you provide |
a warranty) and that users may redistribute the program under |
these conditions, and telling the user how to view a copy of this |
License. (Exception: if the Program itself is interactive but |
does not normally print such an announcement, your work based on |
the Program is not required to print an announcement.) |
These requirements apply to the modified work as a whole. If |
identifiable sections of that work are not derived from the Program, |
and can be reasonably considered independent and separate works in |
themselves, then this License, and its terms, do not apply to those |
sections when you distribute them as separate works. But when you |
distribute the same sections as part of a whole which is a work based |
on the Program, the distribution of the whole must be on the terms of |
this License, whose permissions for other licensees extend to the |
entire whole, and thus to each and every part regardless of who wrote it. |
Thus, it is not the intent of this section to claim rights or contest |
your rights to work written entirely by you; rather, the intent is to |
exercise the right to control the distribution of derivative or |
collective works based on the Program. |
In addition, mere aggregation of another work not based on the Program |
with the Program (or with a work based on the Program) on a volume of |
a storage or distribution medium does not bring the other work under |
the scope of this License. |
3. You may copy and distribute the Program (or a work based on it, |
under Section 2) in object code or executable form under the terms of |
Sections 1 and 2 above provided that you also do one of the following: |
a) Accompany it with the complete corresponding machine-readable |
source code, which must be distributed under the terms of Sections |
1 and 2 above on a medium customarily used for software interchange; or, |
b) Accompany it with a written offer, valid for at least three |
years, to give any third party, for a charge no more than your |
cost of physically performing source distribution, a complete |
machine-readable copy of the corresponding source code, to be |
distributed under the terms of Sections 1 and 2 above on a medium |
customarily used for software interchange; or, |
c) Accompany it with the information you received as to the offer |
to distribute corresponding source code. (This alternative is |
allowed only for noncommercial distribution and only if you |
received the program in object code or executable form with such |
an offer, in accord with Subsection b above.) |
The source code for a work means the preferred form of the work for |
making modifications to it. For an executable work, complete source |
code means all the source code for all modules it contains, plus any |
associated interface definition files, plus the scripts used to |
control compilation and installation of the executable. However, as a |
special exception, the source code distributed need not include |
anything that is normally distributed (in either source or binary |
form) with the major components (compiler, kernel, and so on) of the |
operating system on which the executable runs, unless that component |
itself accompanies the executable. |
If distribution of executable or object code is made by offering |
access to copy from a designated place, then offering equivalent |
access to copy the source code from the same place counts as |
distribution of the source code, even though third parties are not |
compelled to copy the source along with the object code. |
4. You may not copy, modify, sublicense, or distribute the Program |
except as expressly provided under this License. Any attempt |
otherwise to copy, modify, sublicense or distribute the Program is |
void, and will automatically terminate your rights under this License. |
However, parties who have received copies, or rights, from you under |
this License will not have their licenses terminated so long as such |
parties remain in full compliance. |
5. You are not required to accept this License, since you have not |
signed it. However, nothing else grants you permission to modify or |
distribute the Program or its derivative works. These actions are |
prohibited by law if you do not accept this License. Therefore, by |
modifying or distributing the Program (or any work based on the |
Program), you indicate your acceptance of this License to do so, and |
all its terms and conditions for copying, distributing or modifying |
the Program or works based on it. |
6. Each time you redistribute the Program (or any work based on the |
Program), the recipient automatically receives a license from the |
original licensor to copy, distribute or modify the Program subject to |
these terms and conditions. You may not impose any further |
restrictions on the recipients' exercise of the rights granted herein. |
You are not responsible for enforcing compliance by third parties to |
this License. |
7. If, as a consequence of a court judgment or allegation of patent |
infringement or for any other reason (not limited to patent issues), |
conditions are imposed on you (whether by court order, agreement or |
otherwise) that contradict the conditions of this License, they do not |
excuse you from the conditions of this License. If you cannot |
distribute so as to satisfy simultaneously your obligations under this |
License and any other pertinent obligations, then as a consequence you |
may not distribute the Program at all. For example, if a patent |
license would not permit royalty-free redistribution of the Program by |
all those who receive copies directly or indirectly through you, then |
the only way you could satisfy both it and this License would be to |
refrain entirely from distribution of the Program. |
If any portion of this section is held invalid or unenforceable under |
any particular circumstance, the balance of the section is intended to |
apply and the section as a whole is intended to apply in other |
circumstances. |
It is not the purpose of this section to induce you to infringe any |
patents or other property right claims or to contest validity of any |
such claims; this section has the sole purpose of protecting the |
integrity of the free software distribution system, which is |
implemented by public license practices. Many people have made |
generous contributions to the wide range of software distributed |
through that system in reliance on consistent application of that |
system; it is up to the author/donor to decide if he or she is willing |
to distribute software through any other system and a licensee cannot |
impose that choice. |
This section is intended to make thoroughly clear what is believed to |
be a consequence of the rest of this License. |
8. If the distribution and/or use of the Program is restricted in |
certain countries either by patents or by copyrighted interfaces, the |
original copyright holder who places the Program under this License |
may add an explicit geographical distribution limitation excluding |
those countries, so that distribution is permitted only in or among |
countries not thus excluded. In such case, this License incorporates |
the limitation as if written in the body of this License. |
9. The Free Software Foundation may publish revised and/or new versions |
of the General Public License from time to time. Such new versions will |
be similar in spirit to the present version, but may differ in detail to |
address new problems or concerns. |
Each version is given a distinguishing version number. If the Program |
specifies a version number of this License which applies to it and "any |
later version", you have the option of following the terms and conditions |
either of that version or of any later version published by the Free |
Software Foundation. If the Program does not specify a version number of |
this License, you may choose any version ever published by the Free Software |
Foundation. |
10. If you wish to incorporate parts of the Program into other free |
programs whose distribution conditions are different, write to the author |
to ask for permission. For software which is copyrighted by the Free |
Software Foundation, write to the Free Software Foundation; we sometimes |
make exceptions for this. Our decision will be guided by the two goals |
of preserving the free status of all derivatives of our free software and |
of promoting the sharing and reuse of software generally. |
NO WARRANTY |
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY |
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN |
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES |
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED |
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS |
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE |
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, |
REPAIR OR CORRECTION. |
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING |
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR |
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, |
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING |
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED |
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY |
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER |
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE |
POSSIBILITY OF SUCH DAMAGES. |
END OF TERMS AND CONDITIONS |
Appendix: How to Apply These Terms to Your New Programs |
If you develop a new program, and you want it to be of the greatest |
possible use to the public, the best way to achieve this is to make it |
free software which everyone can redistribute and change under these terms. |
To do so, attach the following notices to the program. It is safest |
to attach them to the start of each source file to most effectively |
convey the exclusion of warranty; and each file should have at least |
the "copyright" line and a pointer to where the full notice is found. |
<one line to give the program's name and a brief idea of what it does.> |
Copyright (C) 19yy <name of author> |
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 2 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
Also add information on how to contact you by electronic and paper mail. |
If the program is interactive, make it output a short notice like this |
when it starts in an interactive mode: |
Gnomovision version 69, Copyright (C) 19yy name of author |
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. |
This is free software, and you are welcome to redistribute it |
under certain conditions; type `show c' for details. |
The hypothetical commands `show w' and `show c' should show the appropriate |
parts of the General Public License. Of course, the commands you use may |
be called something other than `show w' and `show c'; they could even be |
mouse-clicks or menu items--whatever suits your program. |
You should also get your employer (if you work as a programmer) or your |
school, if any, to sign a "copyright disclaimer" for the program, if |
necessary. Here is a sample; alter the names: |
Yoyodyne, Inc., hereby disclaims all copyright interest in the program |
`Gnomovision' (which makes passes at compilers) written by James Hacker. |
<signature of Ty Coon>, 1 April 1989 |
Ty Coon, President of Vice |
This General Public License does not permit incorporating your program into |
proprietary programs. If your program is a subroutine library, you may |
consider it more useful to permit linking proprietary applications with the |
library. If this is what you want to do, use the GNU Library General |
Public License instead of this License. |
/incron/tags/incron-0.3.0/COPYING |
---|
0,0 → 1,11 |
inotify cron system |
Copyright (C) 2006 Lukas Jelinek, <lukas@aiken.cz> |
This program is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public License, |
version 2 (see LICENSE-GPL). |
The program uses some parts covered also by other licenses. |
Please look into the source files for detailed information. |
/incron/tags/incron-0.3.0/LICENSE-LGPL |
---|
0,0 → 1,504 |
GNU LESSER GENERAL PUBLIC LICENSE |
Version 2.1, February 1999 |
Copyright (C) 1991, 1999 Free Software Foundation, Inc. |
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
Everyone is permitted to copy and distribute verbatim copies |
of this license document, but changing it is not allowed. |
[This is the first released version of the Lesser GPL. It also counts |
as the successor of the GNU Library Public License, version 2, hence |
the version number 2.1.] |
Preamble |
The licenses for most software are designed to take away your |
freedom to share and change it. By contrast, the GNU General Public |
Licenses are intended to guarantee your freedom to share and change |
free software--to make sure the software is free for all its users. |
This license, the Lesser General Public License, applies to some |
specially designated software packages--typically libraries--of the |
Free Software Foundation and other authors who decide to use it. You |
can use it too, but we suggest you first think carefully about whether |
this license or the ordinary General Public License is the better |
strategy to use in any particular case, based on the explanations below. |
When we speak of free software, we are referring to freedom of use, |
not price. Our General Public Licenses are designed to make sure that |
you have the freedom to distribute copies of free software (and charge |
for this service if you wish); that you receive source code or can get |
it if you want it; that you can change the software and use pieces of |
it in new free programs; and that you are informed that you can do |
these things. |
To protect your rights, we need to make restrictions that forbid |
distributors to deny you these rights or to ask you to surrender these |
rights. These restrictions translate to certain responsibilities for |
you if you distribute copies of the library or if you modify it. |
For example, if you distribute copies of the library, whether gratis |
or for a fee, you must give the recipients all the rights that we gave |
you. You must make sure that they, too, receive or can get the source |
code. If you link other code with the library, you must provide |
complete object files to the recipients, so that they can relink them |
with the library after making changes to the library and recompiling |
it. And you must show them these terms so they know their rights. |
We protect your rights with a two-step method: (1) we copyright the |
library, and (2) we offer you this license, which gives you legal |
permission to copy, distribute and/or modify the library. |
To protect each distributor, we want to make it very clear that |
there is no warranty for the free library. Also, if the library is |
modified by someone else and passed on, the recipients should know |
that what they have is not the original version, so that the original |
author's reputation will not be affected by problems that might be |
introduced by others. |
Finally, software patents pose a constant threat to the existence of |
any free program. We wish to make sure that a company cannot |
effectively restrict the users of a free program by obtaining a |
restrictive license from a patent holder. Therefore, we insist that |
any patent license obtained for a version of the library must be |
consistent with the full freedom of use specified in this license. |
Most GNU software, including some libraries, is covered by the |
ordinary GNU General Public License. This license, the GNU Lesser |
General Public License, applies to certain designated libraries, and |
is quite different from the ordinary General Public License. We use |
this license for certain libraries in order to permit linking those |
libraries into non-free programs. |
When a program is linked with a library, whether statically or using |
a shared library, the combination of the two is legally speaking a |
combined work, a derivative of the original library. The ordinary |
General Public License therefore permits such linking only if the |
entire combination fits its criteria of freedom. The Lesser General |
Public License permits more lax criteria for linking other code with |
the library. |
We call this license the "Lesser" General Public License because it |
does Less to protect the user's freedom than the ordinary General |
Public License. It also provides other free software developers Less |
of an advantage over competing non-free programs. These disadvantages |
are the reason we use the ordinary General Public License for many |
libraries. However, the Lesser license provides advantages in certain |
special circumstances. |
For example, on rare occasions, there may be a special need to |
encourage the widest possible use of a certain library, so that it becomes |
a de-facto standard. To achieve this, non-free programs must be |
allowed to use the library. A more frequent case is that a free |
library does the same job as widely used non-free libraries. In this |
case, there is little to gain by limiting the free library to free |
software only, so we use the Lesser General Public License. |
In other cases, permission to use a particular library in non-free |
programs enables a greater number of people to use a large body of |
free software. For example, permission to use the GNU C Library in |
non-free programs enables many more people to use the whole GNU |
operating system, as well as its variant, the GNU/Linux operating |
system. |
Although the Lesser General Public License is Less protective of the |
users' freedom, it does ensure that the user of a program that is |
linked with the Library has the freedom and the wherewithal to run |
that program using a modified version of the Library. |
The precise terms and conditions for copying, distribution and |
modification follow. Pay close attention to the difference between a |
"work based on the library" and a "work that uses the library". The |
former contains code derived from the library, whereas the latter must |
be combined with the library in order to run. |
GNU LESSER GENERAL PUBLIC LICENSE |
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION |
0. This License Agreement applies to any software library or other |
program which contains a notice placed by the copyright holder or |
other authorized party saying it may be distributed under the terms of |
this Lesser General Public License (also called "this License"). |
Each licensee is addressed as "you". |
A "library" means a collection of software functions and/or data |
prepared so as to be conveniently linked with application programs |
(which use some of those functions and data) to form executables. |
The "Library", below, refers to any such software library or work |
which has been distributed under these terms. A "work based on the |
Library" means either the Library or any derivative work under |
copyright law: that is to say, a work containing the Library or a |
portion of it, either verbatim or with modifications and/or translated |
straightforwardly into another language. (Hereinafter, translation is |
included without limitation in the term "modification".) |
"Source code" for a work means the preferred form of the work for |
making modifications to it. For a library, complete source code means |
all the source code for all modules it contains, plus any associated |
interface definition files, plus the scripts used to control compilation |
and installation of the library. |
Activities other than copying, distribution and modification are not |
covered by this License; they are outside its scope. The act of |
running a program using the Library is not restricted, and output from |
such a program is covered only if its contents constitute a work based |
on the Library (independent of the use of the Library in a tool for |
writing it). Whether that is true depends on what the Library does |
and what the program that uses the Library does. |
1. You may copy and distribute verbatim copies of the Library's |
complete source code as you receive it, in any medium, provided that |
you conspicuously and appropriately publish on each copy an |
appropriate copyright notice and disclaimer of warranty; keep intact |
all the notices that refer to this License and to the absence of any |
warranty; and distribute a copy of this License along with the |
Library. |
You may charge a fee for the physical act of transferring a copy, |
and you may at your option offer warranty protection in exchange for a |
fee. |
2. You may modify your copy or copies of the Library or any portion |
of it, thus forming a work based on the Library, and copy and |
distribute such modifications or work under the terms of Section 1 |
above, provided that you also meet all of these conditions: |
a) The modified work must itself be a software library. |
b) You must cause the files modified to carry prominent notices |
stating that you changed the files and the date of any change. |
c) You must cause the whole of the work to be licensed at no |
charge to all third parties under the terms of this License. |
d) If a facility in the modified Library refers to a function or a |
table of data to be supplied by an application program that uses |
the facility, other than as an argument passed when the facility |
is invoked, then you must make a good faith effort to ensure that, |
in the event an application does not supply such function or |
table, the facility still operates, and performs whatever part of |
its purpose remains meaningful. |
(For example, a function in a library to compute square roots has |
a purpose that is entirely well-defined independent of the |
application. Therefore, Subsection 2d requires that any |
application-supplied function or table used by this function must |
be optional: if the application does not supply it, the square |
root function must still compute square roots.) |
These requirements apply to the modified work as a whole. If |
identifiable sections of that work are not derived from the Library, |
and can be reasonably considered independent and separate works in |
themselves, then this License, and its terms, do not apply to those |
sections when you distribute them as separate works. But when you |
distribute the same sections as part of a whole which is a work based |
on the Library, the distribution of the whole must be on the terms of |
this License, whose permissions for other licensees extend to the |
entire whole, and thus to each and every part regardless of who wrote |
it. |
Thus, it is not the intent of this section to claim rights or contest |
your rights to work written entirely by you; rather, the intent is to |
exercise the right to control the distribution of derivative or |
collective works based on the Library. |
In addition, mere aggregation of another work not based on the Library |
with the Library (or with a work based on the Library) on a volume of |
a storage or distribution medium does not bring the other work under |
the scope of this License. |
3. You may opt to apply the terms of the ordinary GNU General Public |
License instead of this License to a given copy of the Library. To do |
this, you must alter all the notices that refer to this License, so |
that they refer to the ordinary GNU General Public License, version 2, |
instead of to this License. (If a newer version than version 2 of the |
ordinary GNU General Public License has appeared, then you can specify |
that version instead if you wish.) Do not make any other change in |
these notices. |
Once this change is made in a given copy, it is irreversible for |
that copy, so the ordinary GNU General Public License applies to all |
subsequent copies and derivative works made from that copy. |
This option is useful when you wish to copy part of the code of |
the Library into a program that is not a library. |
4. You may copy and distribute the Library (or a portion or |
derivative of it, under Section 2) in object code or executable form |
under the terms of Sections 1 and 2 above provided that you accompany |
it with the complete corresponding machine-readable source code, which |
must be distributed under the terms of Sections 1 and 2 above on a |
medium customarily used for software interchange. |
If distribution of object code is made by offering access to copy |
from a designated place, then offering equivalent access to copy the |
source code from the same place satisfies the requirement to |
distribute the source code, even though third parties are not |
compelled to copy the source along with the object code. |
5. A program that contains no derivative of any portion of the |
Library, but is designed to work with the Library by being compiled or |
linked with it, is called a "work that uses the Library". Such a |
work, in isolation, is not a derivative work of the Library, and |
therefore falls outside the scope of this License. |
However, linking a "work that uses the Library" with the Library |
creates an executable that is a derivative of the Library (because it |
contains portions of the Library), rather than a "work that uses the |
library". The executable is therefore covered by this License. |
Section 6 states terms for distribution of such executables. |
When a "work that uses the Library" uses material from a header file |
that is part of the Library, the object code for the work may be a |
derivative work of the Library even though the source code is not. |
Whether this is true is especially significant if the work can be |
linked without the Library, or if the work is itself a library. The |
threshold for this to be true is not precisely defined by law. |
If such an object file uses only numerical parameters, data |
structure layouts and accessors, and small macros and small inline |
functions (ten lines or less in length), then the use of the object |
file is unrestricted, regardless of whether it is legally a derivative |
work. (Executables containing this object code plus portions of the |
Library will still fall under Section 6.) |
Otherwise, if the work is a derivative of the Library, you may |
distribute the object code for the work under the terms of Section 6. |
Any executables containing that work also fall under Section 6, |
whether or not they are linked directly with the Library itself. |
6. As an exception to the Sections above, you may also combine or |
link a "work that uses the Library" with the Library to produce a |
work containing portions of the Library, and distribute that work |
under terms of your choice, provided that the terms permit |
modification of the work for the customer's own use and reverse |
engineering for debugging such modifications. |
You must give prominent notice with each copy of the work that the |
Library is used in it and that the Library and its use are covered by |
this License. You must supply a copy of this License. If the work |
during execution displays copyright notices, you must include the |
copyright notice for the Library among them, as well as a reference |
directing the user to the copy of this License. Also, you must do one |
of these things: |
a) Accompany the work with the complete corresponding |
machine-readable source code for the Library including whatever |
changes were used in the work (which must be distributed under |
Sections 1 and 2 above); and, if the work is an executable linked |
with the Library, with the complete machine-readable "work that |
uses the Library", as object code and/or source code, so that the |
user can modify the Library and then relink to produce a modified |
executable containing the modified Library. (It is understood |
that the user who changes the contents of definitions files in the |
Library will not necessarily be able to recompile the application |
to use the modified definitions.) |
b) Use a suitable shared library mechanism for linking with the |
Library. A suitable mechanism is one that (1) uses at run time a |
copy of the library already present on the user's computer system, |
rather than copying library functions into the executable, and (2) |
will operate properly with a modified version of the library, if |
the user installs one, as long as the modified version is |
interface-compatible with the version that the work was made with. |
c) Accompany the work with a written offer, valid for at |
least three years, to give the same user the materials |
specified in Subsection 6a, above, for a charge no more |
than the cost of performing this distribution. |
d) If distribution of the work is made by offering access to copy |
from a designated place, offer equivalent access to copy the above |
specified materials from the same place. |
e) Verify that the user has already received a copy of these |
materials or that you have already sent this user a copy. |
For an executable, the required form of the "work that uses the |
Library" must include any data and utility programs needed for |
reproducing the executable from it. However, as a special exception, |
the materials to be distributed need not include anything that is |
normally distributed (in either source or binary form) with the major |
components (compiler, kernel, and so on) of the operating system on |
which the executable runs, unless that component itself accompanies |
the executable. |
It may happen that this requirement contradicts the license |
restrictions of other proprietary libraries that do not normally |
accompany the operating system. Such a contradiction means you cannot |
use both them and the Library together in an executable that you |
distribute. |
7. You may place library facilities that are a work based on the |
Library side-by-side in a single library together with other library |
facilities not covered by this License, and distribute such a combined |
library, provided that the separate distribution of the work based on |
the Library and of the other library facilities is otherwise |
permitted, and provided that you do these two things: |
a) Accompany the combined library with a copy of the same work |
based on the Library, uncombined with any other library |
facilities. This must be distributed under the terms of the |
Sections above. |
b) Give prominent notice with the combined library of the fact |
that part of it is a work based on the Library, and explaining |
where to find the accompanying uncombined form of the same work. |
8. You may not copy, modify, sublicense, link with, or distribute |
the Library except as expressly provided under this License. Any |
attempt otherwise to copy, modify, sublicense, link with, or |
distribute the Library is void, and will automatically terminate your |
rights under this License. However, parties who have received copies, |
or rights, from you under this License will not have their licenses |
terminated so long as such parties remain in full compliance. |
9. You are not required to accept this License, since you have not |
signed it. However, nothing else grants you permission to modify or |
distribute the Library or its derivative works. These actions are |
prohibited by law if you do not accept this License. Therefore, by |
modifying or distributing the Library (or any work based on the |
Library), you indicate your acceptance of this License to do so, and |
all its terms and conditions for copying, distributing or modifying |
the Library or works based on it. |
10. Each time you redistribute the Library (or any work based on the |
Library), the recipient automatically receives a license from the |
original licensor to copy, distribute, link with or modify the Library |
subject to these terms and conditions. You may not impose any further |
restrictions on the recipients' exercise of the rights granted herein. |
You are not responsible for enforcing compliance by third parties with |
this License. |
11. If, as a consequence of a court judgment or allegation of patent |
infringement or for any other reason (not limited to patent issues), |
conditions are imposed on you (whether by court order, agreement or |
otherwise) that contradict the conditions of this License, they do not |
excuse you from the conditions of this License. If you cannot |
distribute so as to satisfy simultaneously your obligations under this |
License and any other pertinent obligations, then as a consequence you |
may not distribute the Library at all. For example, if a patent |
license would not permit royalty-free redistribution of the Library by |
all those who receive copies directly or indirectly through you, then |
the only way you could satisfy both it and this License would be to |
refrain entirely from distribution of the Library. |
If any portion of this section is held invalid or unenforceable under any |
particular circumstance, the balance of the section is intended to apply, |
and the section as a whole is intended to apply in other circumstances. |
It is not the purpose of this section to induce you to infringe any |
patents or other property right claims or to contest validity of any |
such claims; this section has the sole purpose of protecting the |
integrity of the free software distribution system which is |
implemented by public license practices. Many people have made |
generous contributions to the wide range of software distributed |
through that system in reliance on consistent application of that |
system; it is up to the author/donor to decide if he or she is willing |
to distribute software through any other system and a licensee cannot |
impose that choice. |
This section is intended to make thoroughly clear what is believed to |
be a consequence of the rest of this License. |
12. If the distribution and/or use of the Library is restricted in |
certain countries either by patents or by copyrighted interfaces, the |
original copyright holder who places the Library under this License may add |
an explicit geographical distribution limitation excluding those countries, |
so that distribution is permitted only in or among countries not thus |
excluded. In such case, this License incorporates the limitation as if |
written in the body of this License. |
13. The Free Software Foundation may publish revised and/or new |
versions of the Lesser General Public License from time to time. |
Such new versions will be similar in spirit to the present version, |
but may differ in detail to address new problems or concerns. |
Each version is given a distinguishing version number. If the Library |
specifies a version number of this License which applies to it and |
"any later version", you have the option of following the terms and |
conditions either of that version or of any later version published by |
the Free Software Foundation. If the Library does not specify a |
license version number, you may choose any version ever published by |
the Free Software Foundation. |
14. If you wish to incorporate parts of the Library into other free |
programs whose distribution conditions are incompatible with these, |
write to the author to ask for permission. For software which is |
copyrighted by the Free Software Foundation, write to the Free |
Software Foundation; we sometimes make exceptions for this. Our |
decision will be guided by the two goals of preserving the free status |
of all derivatives of our free software and of promoting the sharing |
and reuse of software generally. |
NO WARRANTY |
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO |
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. |
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR |
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY |
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE |
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE |
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME |
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. |
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN |
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY |
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU |
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR |
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE |
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING |
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A |
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF |
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
DAMAGES. |
END OF TERMS AND CONDITIONS |
How to Apply These Terms to Your New Libraries |
If you develop a new library, and you want it to be of the greatest |
possible use to the public, we recommend making it free software that |
everyone can redistribute and change. You can do so by permitting |
redistribution under these terms (or, alternatively, under the terms of the |
ordinary General Public License). |
To apply these terms, attach the following notices to the library. It is |
safest to attach them to the start of each source file to most effectively |
convey the exclusion of warranty; and each file should have at least the |
"copyright" line and a pointer to where the full notice is found. |
<one line to give the library's name and a brief idea of what it does.> |
Copyright (C) <year> <name of author> |
This library is free software; you can redistribute it and/or |
modify it under the terms of the GNU Lesser General Public |
License as published by the Free Software Foundation; either |
version 2.1 of the License, or (at your option) any later version. |
This library is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
Lesser General Public License for more details. |
You should have received a copy of the GNU Lesser General Public |
License along with this library; if not, write to the Free Software |
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
Also add information on how to contact you by electronic and paper mail. |
You should also get your employer (if you work as a programmer) or your |
school, if any, to sign a "copyright disclaimer" for the library, if |
necessary. Here is a sample; alter the names: |
Yoyodyne, Inc., hereby disclaims all copyright interest in the |
library `Frob' (a library for tweaking knobs) written by James Random Hacker. |
<signature of Ty Coon>, 1 April 1990 |
Ty Coon, President of Vice |
That's all there is to it! |