/incron/trunk/ict-main.cpp |
---|
0,0 → 1,371 |
/// 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 "incrontab.h" |
// #define INCRON_DEFAULT_EDITOR "nano" // for vim haters like me ;-) |
#define INCRON_DEFAULT_EDITOR "vim" |
const char* argp_program_version = "incrontab 0.1.0"; |
const char* argp_program_bug_address = "<bugs@aiken.cz>"; |
static char doc[] = "Table manipulator for incrond (inotify Cron daemon)"; |
static char args_doc[] = "FILE"; |
static struct argp_option options[] = { |
{"list", 'l', 0, 0, "List current table" }, |
{"remove", 'r', 0, 0, "Remove table completely" }, |
{"edit", 'e', 0, 0, "Edit table" }, |
{"user", 'u', "USER", 0, "Override current user" }, |
{ 0 } |
}; |
enum |
{ |
OPER_NONE, |
OPER_LIST, |
OPER_REMOVE, |
OPER_EDIT |
}; |
struct arguments |
{ |
char *user; |
int oper; |
char *file; |
}; |
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; |
} |
static struct argp argp = { options, parse_opt, args_doc, doc }; |
void unlink_suid(const char* file, uid_t uid) |
{ |
uid_t iu = geteuid(); |
seteuid(uid); |
unlink(file); |
seteuid(iu); |
} |
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; |
} |
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; |
} |
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; |
} |
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: %s\n", 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/trunk/CHANGELOG |
---|
0,0 → 1,2 |
0.1.0 2006-09-15 |
first alpha version |
/incron/trunk/LICENSE-X11 |
---|
0,0 → 1,25 |
Copyright (C) 1996 X Consortium |
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 X CONSORTIUM 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. |
Except as contained in this notice, the name of the X Consortium shall |
not be used in advertising or otherwise to promote the sale, use or |
other dealings in this Software without prior written authorization from |
the X Consortium. |
/incron/trunk/README |
---|
0,0 → 1,94 |
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, 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 |
Example: 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 $@/$# |
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/trunk/incrontab.cpp |
---|
0,0 → 1,170 |
/// 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" |
#define INCRON_ALLOW_PATH "/etc/incron.allow" |
#define INCRON_DENY_PATH "/etc/incron.deny" |
InCronTabEntry::InCronTabEntry() |
: m_uMask(0) |
{ |
} |
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 = "0"; |
ss << m_path << " " << m << " " << m_cmd; |
return ss.str(); |
} |
bool InCronTabEntry::Parse(const std::string& rStr, InCronTabEntry& rEntry) |
{ |
char s1[1000], s2[1000], s3[1000]; |
unsigned long u; |
if (sscanf(rStr.c_str(), "%s %s %[^\n]", s1, s2, s3) != 3) |
return false; |
rEntry.m_path = s1; |
rEntry.m_cmd = s3; |
rEntry.m_uMask = 0; |
if (sscanf(s2, "%lu", &u) == 1) { |
rEntry.m_uMask = (uint32_t) u; |
} |
else { |
StringTokenizer tok(s2); |
while (tok.HasMoreTokens()) { |
rEntry.m_uMask |= InotifyEvent::GetMaskByName(tok.GetNextToken()); |
} |
} |
return true; |
} |
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/trunk/inotify-cxx.cpp |
---|
0,0 → 1,284 |
/// 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 "inotify-cxx.h" |
#define DUMP_SEP \ |
({ \ |
if (!rStr.empty()) { \ |
rStr.append(","); \ |
} \ |
}) |
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_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; |
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"); |
} |
} |
void InotifyEvent::DumpTypes(std::string& rStr) const |
{ |
DumpTypes((uint32_t) m_evt.mask, rStr); |
} |
Inotify::Inotify() |
{ |
m_fd = inotify_init(); |
} |
Inotify::~Inotify() |
{ |
Close(); |
} |
void Inotify::Close() |
{ |
if (m_fd != -1) { |
RemoveAll(); |
close(m_fd); |
m_fd = -1; |
} |
} |
bool Inotify::Add(InotifyWatch* pWatch) |
{ |
if (m_fd == -1) |
return false; |
pWatch->m_wd = inotify_add_watch(m_fd, pWatch->GetPath().c_str(), pWatch->GetMask()); |
if (pWatch->m_wd != -1) { |
m_watches.insert(IN_WATCH_MAP::value_type(pWatch->m_wd, pWatch)); |
pWatch->m_pInotify = this; |
return true; |
} |
return false; |
} |
void Inotify::Remove(InotifyWatch* pWatch) |
{ |
if (m_fd == -1) |
return; |
if (inotify_rm_watch(m_fd, pWatch->GetMask()) != -1) { |
m_watches.erase(pWatch->m_wd); |
pWatch->m_wd = -1; |
pWatch->m_pInotify = NULL; |
} |
} |
void Inotify::RemoveAll() |
{ |
IN_WATCH_MAP::iterator it = m_watches.begin(); |
while (it != m_watches.end()) { |
InotifyWatch* pW = (*it).second; |
inotify_rm_watch(m_fd, pW->GetMask()); |
pW->m_wd = -1; |
pW->m_pInotify = NULL; |
it++; |
} |
m_watches.clear(); |
} |
bool Inotify::WaitForEvents(bool fNoIntr) |
{ |
ssize_t len = 0; |
do { |
len = read(m_fd, m_buf, INOTIFY_BUFLEN); |
} while (fNoIntr && len == -1 && errno == EINTR); |
if (len <= 0) { |
return false; |
} |
ssize_t i = 0; |
while (i < len) { |
InotifyWatch* pW = FindWatch(((struct inotify_event *) &m_buf[i])->wd); |
InotifyEvent evt((struct inotify_event *) &m_buf[i], pW); |
m_events.push_back(evt); |
i += INOTIFY_EVENT_SIZE + (int) evt.GetLength(); |
} |
return true; |
} |
int Inotify::GetEventCount() |
{ |
return m_events.size(); |
} |
bool Inotify::GetEvent(InotifyEvent* pEvt) |
{ |
bool b = PeekEvent(pEvt); |
if (b) |
m_events.pop_front(); |
return b; |
} |
bool Inotify::PeekEvent(InotifyEvent* pEvt) |
{ |
if (pEvt == NULL || m_events.empty()) |
return false; |
*pEvt = m_events.front(); |
return true; |
} |
InotifyWatch* Inotify::FindWatch(int iDescriptor) |
{ |
IN_WATCH_MAP::iterator it = m_watches.find(iDescriptor); |
if (it == m_watches.end()) |
return NULL; |
return (*it).second; |
} |
/incron/trunk/icd-main.cpp |
---|
0,0 → 1,173 |
/// 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 "inotify-cxx.h" |
#include "incrontab.h" |
#include "usertable.h" |
#define DAEMON false |
#define INCRON_APP_NAME "incrond" |
#define INCRON_LOG_OPTS (LOG_CONS | LOG_PID) |
#define INCRON_LOG_FACIL LOG_CRON |
typedef std::map<std::string, UserTable*> SUT_MAP; |
SUT_MAP g_ut; |
bool g_fFinish = false; |
void on_signal(int signo) |
{ |
g_fFinish = true; |
} |
void on_child(int signo) |
{ |
wait(NULL); |
} |
bool check_user(const char* user) |
{ |
struct passwd* pw = getpwnam(user); |
if (pw == NULL) |
return false; |
return InCronTab::CheckUser(user); |
} |
bool load_tables(Inotify* pIn, EventDispatcher* pEd) |
{ |
DIR* d = opendir(INCRON_TABLE_BASE); |
if (d == NULL) { |
syslog(LOG_CRIT, "cannot open table directory: %s", strerror(errno)); |
return false; |
} |
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); |
return true; |
} |
int main(int argc, char** argv) |
{ |
openlog(INCRON_APP_NAME, INCRON_LOG_OPTS, INCRON_LOG_FACIL); |
syslog(LOG_NOTICE, "starting service"); |
Inotify in; |
EventDispatcher ed(&in); |
if (!load_tables(&in, &ed)) { |
closelog(); |
return 1; |
} |
signal(SIGTERM, on_signal); |
signal(SIGINT, on_signal); |
signal(SIGCHLD, on_child); |
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; |
while (!g_fFinish) { |
if (in.WaitForEvents()) { |
while (in.GetEvent(e)) { |
std::string s; |
e.DumpTypes(s); |
//syslog(LOG_DEBUG, "EVENT: wd=%i, cookie=%u, name=%s, mask: %s", (int) e.GetDescriptor(), (unsigned) e.GetCookie(), e.GetName().c_str(), s.c_str()); |
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); |
} |
} |
} |
} |
syslog(LOG_NOTICE, "stopping service"); |
closelog(); |
return 0; |
} |
/incron/trunk/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/trunk/incrontab.h |
---|
0,0 → 1,111 |
/// 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" |
#define INCRON_TABLE_BASE "/var/spool/incron/" |
class InCronTabEntry |
{ |
public: |
InCronTabEntry(); |
InCronTabEntry(const std::string& rPath, uint32_t uMask, const std::string& rCmd); |
~InCronTabEntry() {} |
std::string ToString() const; |
static bool Parse(const std::string& rStr, InCronTabEntry& rEntry); |
inline const std::string& GetPath() const |
{ |
return m_path; |
} |
inline int32_t GetMask() const |
{ |
return m_uMask; |
} |
inline const std::string& GetCmd() const |
{ |
return m_cmd; |
} |
protected: |
std::string m_path; |
uint32_t m_uMask; |
std::string m_cmd; |
}; |
class InCronTab |
{ |
public: |
InCronTab() {} |
~InCronTab() {} |
inline void Add(const InCronTabEntry& rEntry) |
{ |
m_tab.push_back(rEntry); |
} |
inline void Clear() |
{ |
m_tab.clear(); |
} |
inline bool IsEmpty() const |
{ |
return m_tab.empty(); |
} |
inline int GetCount() const |
{ |
return (int) m_tab.size(); |
} |
inline InCronTabEntry& GetEntry(int index) |
{ |
return m_tab[index]; |
} |
bool Load(const std::string& rPath); |
bool Save(const std::string& rPath); |
static bool CheckUser(const std::string& rUser); |
static std::string GetUserTablePath(const std::string& rUser); |
protected: |
std::deque<InCronTabEntry> m_tab; |
}; |
#endif //_INCRONTAB_H_ |
/incron/trunk/usertable.cpp |
---|
0,0 → 1,236 |
/// 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 "usertable.h" |
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()) |
return; |
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()); |
m_pIn->Add(pW); |
m_pEd->Register(pW, this); |
m_map.insert(IWCE_MAP::value_type(pW, &rE)); |
} |
} |
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 if (cs[px] == '@') { |
cmd.append(cs.substr(oldpos, pos-oldpos)); |
cmd.append(pW->GetPath()); |
oldpos = pos + 2; |
} |
else if (cs[px] == '#') { |
cmd.append(cs.substr(oldpos, pos-oldpos)); |
cmd.append(rEvt.GetName()); |
oldpos = pos + 2; |
} |
else { |
cmd.append(cs.substr(oldpos, pos-oldpos)); |
oldpos = pos + 1; |
} |
} |
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()); |
pid_t pid = fork(); |
if (pid == 0) { |
struct passwd* pwd = getpwnam(m_user.c_str()); |
if (pwd == NULL) |
_exit(1); |
if (setuid(pwd->pw_uid) != 0) |
_exit(1); |
if (execvp(argv[0], argv) != 0) { |
_exit(1); |
} |
} |
else if (pid > 0) { |
} |
else { |
syslog(LOG_ERR, "cannot fork process: %s", strerror(errno)); |
} |
} |
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; |
} |
/incron/trunk/strtok.cpp |
---|
0,0 → 1,50 |
/// 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 "strtok.h" |
typedef std::string::size_type SIZE; |
StringTokenizer::StringTokenizer(const std::string& rStr, char cDelim) |
{ |
m_str = rStr; |
m_cDelim = cDelim; |
m_pos = 0; |
m_len = rStr.length(); |
} |
std::string StringTokenizer::GetNextToken() |
{ |
std::string s; |
for (SIZE i=m_pos; i<m_len; i++) { |
if (m_str[i] == m_cDelim) { |
s = m_str.substr(m_pos, i - m_pos); |
m_pos = i + 1; |
return s; |
} |
} |
s = m_str.substr(m_pos); |
m_pos = m_len; |
return s; |
} |
/incron/trunk/inotify-cxx.h |
---|
0,0 → 1,459 |
/// 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/inotify.h> |
#include <sys/inotify-syscalls.h> |
/// Event struct size |
#define INOTIFY_EVENT_SIZE (sizeof(struct inotify_event)) |
/// Event buffer length |
#define INOTIFY_BUFLEN (1024 * (INOTIFY_EVENT_SIZE + 16)) |
// forward declaration |
class InotifyWatch; |
class Inotify; |
/// inotify event class |
/** |
* It holds all information about inotify event and provides |
* access to its particular values. |
*/ |
class InotifyEvent |
{ |
public: |
/// Constructor. |
/** |
* Creates a plain event. |
*/ |
InotifyEvent() |
{ |
memset(&m_evt, 0, sizeof(m_evt)); |
m_evt.wd = (int32_t) -1; |
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) |
{ |
if (pEvt != NULL) { |
memcpy(&m_evt, pEvt, sizeof(m_evt)); |
if (pEvt->name != NULL) |
m_name = pEvt->name; |
m_pWatch = pWatch; |
} |
else { |
memset(&m_evt, 0, sizeof(m_evt)); |
m_evt.wd = (int32_t) -1; |
m_pWatch = NULL; |
} |
} |
/// Destructor. |
~InotifyEvent() {} |
/// Returns the event watch descriptor. |
/** |
* \return watch descriptor |
* |
* \sa InotifyWatch::GetDescriptor() |
*/ |
inline int32_t GetDescriptor() const |
{ |
return (int32_t) m_evt.wd; |
} |
/// Returns the event mask. |
/** |
* \return event mask |
* |
* \sa InotifyWatch::GetMask() |
*/ |
inline uint32_t GetMask() const |
{ |
return (uint32_t) m_evt.mask; |
} |
/// 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((uint32_t) m_evt.mask, uType); |
} |
/// Returns the event cookie. |
/** |
* \return event cookie |
*/ |
inline uint32_t GetCookie() const |
{ |
return (uint32_t) m_evt.cookie; |
} |
/// Returns the event name length. |
/** |
* \return event name length |
*/ |
inline uint32_t GetLength() const |
{ |
return (uint32_t) m_evt.len; |
} |
/// 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; |
} |
/// Returns the event raw data. |
/** |
* For NULL pointer it does nothing. |
* |
* \param[in,out] pEvt event data |
*/ |
inline void GetData(struct inotify_event* pEvt) |
{ |
if (pEvt != NULL) |
memcpy(pEvt, &m_evt, sizeof(m_evt)); |
} |
/// Returns the event raw data. |
/** |
* \param[in,out] rEvt event data |
*/ |
inline void GetData(struct inotify_event& rEvt) |
{ |
memcpy(&rEvt, &m_evt, sizeof(m_evt)); |
} |
/// 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: |
struct inotify_event m_evt; ///< event structure |
std::string m_name; ///< event name |
InotifyWatch* m_pWatch; ///< source watch |
}; |
/// inotify watch class |
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 |
*/ |
InotifyWatch(const std::string& rPath, int32_t uMask) |
{ |
m_path = rPath; |
m_uMask = uMask; |
m_wd = (int32_t) -1; |
} |
/// Destructor. |
~InotifyWatch() {} |
/// 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; |
} |
/// Returns the appropriate inotify class instance. |
/** |
* \return inotify instance |
*/ |
inline Inotify* GetInotify() |
{ |
return m_pInotify; |
} |
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 |
}; |
/// Mapping from watch descriptors to watch objects. |
typedef std::map<int32_t, InotifyWatch*> IN_WATCH_MAP; |
/// inotify class |
class Inotify |
{ |
public: |
/// Constructor. |
/** |
* Creates and initializes an instance of inotify communication |
* object (opens the inotify device). |
*/ |
Inotify(); |
/// Destructor. |
/** |
* Calls Close() due for clean-up. |
*/ |
~Inotify(); |
/// Removes all watches and closes the inotify device. |
void Close(); |
/// Checks whether the inotify is ready. |
/** |
* \return true = initialized properly, false = something failed |
*/ |
inline bool IsReady() const |
{ |
return m_fd != -1; |
} |
/// Adds a new watch. |
/** |
* \param[in] pWatch inotify watch |
* \return true = success, false = failure |
*/ |
bool Add(InotifyWatch* pWatch); |
/// Adds a new watch. |
/** |
* \param[in] rWatch inotify watch |
* \return true = success, false = failure |
*/ |
inline bool Add(InotifyWatch& rWatch) |
{ |
return Add(&rWatch); |
} |
/// Removes a watch. |
/** |
* If the given watch is not present it does nothing. |
* |
* \param[in] pWatch inotify watch |
*/ |
void Remove(InotifyWatch* pWatch); |
/// Removes a watch. |
/** |
* If the given watch is not present it does nothing. |
* |
* \param[in] rWatch inotify watch |
*/ |
inline void Remove(InotifyWatch& rWatch) |
{ |
Remove(&rWatch); |
} |
/// Removes all watches. |
void RemoveAll(); |
/// Returns the count of watches. |
/** |
* \return count of watches |
*/ |
inline size_t GetWatchCount() const |
{ |
return (size_t) m_watches.size(); |
} |
/// Waits for inotify events. |
/** |
* It waits until one or more events occur. |
* |
* \param[in] fNoIntr if true it re-calls the system call after a handled signal |
* \return true = event(s) occurred, false = failure |
*/ |
bool WaitForEvents(bool fNoIntr = false); |
/// 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 |
*/ |
int GetEventCount(); |
/// 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 |
* \return true = success, false = failure |
*/ |
bool GetEvent(InotifyEvent* pEvt); |
/// Extracts a queued inotify event. |
/** |
* The extracted event is removed from the queue. |
* |
* \param[in,out] rEvt event object |
* \return true = success, false = failure |
*/ |
bool GetEvent(InotifyEvent& rEvt) |
{ |
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 |
* \return true = success, false = failure |
*/ |
bool PeekEvent(InotifyEvent* pEvt); |
/// Extracts a queued inotify event (without removing). |
/** |
* The extracted event stays in the queue. |
* |
* \param[in,out] rEvt event object |
* \return true = success, false = failure |
*/ |
bool PeekEvent(InotifyEvent& rEvt) |
{ |
return PeekEvent(&rEvt); |
} |
/// Searches for a watch. |
/** |
* It tries to find a watch by the given descriptor. |
* |
* \param[in] iDescriptor watch descriptor |
* \return found descriptor; NULL if no such watch exists |
*/ |
InotifyWatch* FindWatch(int iDescriptor); |
private: |
int m_fd; ///< file descriptor |
IN_WATCH_MAP m_watches; ///< watches |
unsigned char m_buf[INOTIFY_BUFLEN]; ///< buffer for events |
std::deque<InotifyEvent> m_events; ///< event queue |
}; |
#endif //_INOTIFYCXX_H_ |
/incron/trunk/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/trunk/strtok.h |
---|
0,0 → 1,67 |
/// 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> |
class StringTokenizer |
{ |
public: |
StringTokenizer(const std::string& rStr, char cDelim = ','); |
~StringTokenizer() {} |
inline bool HasMoreTokens() const |
{ |
return m_pos < m_len; |
} |
std::string GetNextToken(); |
inline void SetDelimiter(char cDelim) |
{ |
m_cDelim = cDelim; |
} |
inline char GetDelimiter() const |
{ |
return m_cDelim; |
} |
inline void Reset() |
{ |
m_pos = 0; |
} |
private: |
std::string m_str; |
char m_cDelim; |
std::string::size_type m_pos; |
std::string::size_type m_len; |
}; |
#endif //_STRTOK_H_ |
/incron/trunk/usertable.h |
---|
0,0 → 1,77 |
/// 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 "inotify-cxx.h" |
#include "incrontab.h" |
class UserTable; |
typedef std::map<InotifyWatch*, UserTable*> IWUT_MAP; |
typedef std::map<InotifyWatch*, InCronTabEntry*> IWCE_MAP; |
class EventDispatcher |
{ |
public: |
EventDispatcher(Inotify* pIn); |
~EventDispatcher() {} |
void DispatchEvent(InotifyEvent& rEvt); |
void Register(InotifyWatch* pWatch, UserTable* pTab); |
void Unregister(InotifyWatch* pWatch); |
void UnregisterAll(UserTable* pTab); |
private: |
Inotify* m_pIn; |
IWUT_MAP m_maps; |
UserTable* FindTable(InotifyWatch* pW); |
}; |
class UserTable |
{ |
public: |
UserTable(Inotify* pIn, EventDispatcher* pEd, const std::string& rUser); |
virtual ~UserTable(); |
void Load(); |
void Dispose(); |
void OnEvent(InotifyEvent& rEvt); |
private: |
Inotify* m_pIn; |
EventDispatcher* m_pEd; |
std::string m_user; |
InCronTab m_tab; |
IWCE_MAP m_map; |
InCronTabEntry* FindEntry(InotifyWatch* pWatch); |
bool PrepareArgs(const std::string& rCmd, int& argc, char**& argv); |
}; |
#endif //_USERTABLE_H_ |
/incron/trunk/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) |
$(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 |
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 |
strtok.o: strtok.cpp strtok.h |
/incron/trunk/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! |