configureable inotifies

This commit is contained in:
Axel Kittenberger 2010-08-05 11:22:12 +00:00
parent c2354ede16
commit ac5357ea5e
2 changed files with 113 additions and 20 deletions

View File

@ -120,6 +120,12 @@ man(1), man(7), http://www.tldp.org/HOWTO/Man-Page/
<para>With a <option>&lt;callopts&gt;</option> node you can control the arguments lsyncd will call the &lt;binary&gt; (rsync) with. Each child node will specify one argument. &lt;option&gt; specifies a literal argument. Only %r will be replaced with 'r' when rsycnd is supposed to work recursive (on startup of lsyncd) or 'd' on normal operations. &lt;exclude-file&gt; will be replaced with <option>--exclude-from [FILE]</option> if an &lt;exclude-from&gt; file is specified. &lt;source&gt; will be replaced the source directory to sync from. &lt;destination&gt; will be replace to the target to sync to. Default arguments are <option>-lt%r --delete {--exclude-from [FILE]} [SOURCE] [DIRECTORY]</option>.</para>
<programlisting> &lt;callopts&gt;
<para>With a <option>&lt;inotify&gt;</option> node you can control the inotify events lsyncd will register to. Each event is configured by a &lt;event&gt; child node and its attribute 'id'. The following events may be registered: ACCESS,ATTRIB,CLOSE_WRITE,CLOSE_NOWRITE,CREATE,DELETE,DELETE_SELF,MODIFY,MOVE_SELF,MOVED_FROM,MOVED_TO,OPEN. If the inotify node is omitted the following events are registered by default: IN_ATTRIB,IN_CLOSE_WRITE,IN_CREATE,IN_DELETE,IN_DELETE_SELF,IN_MOVED_FROM,IN_MOVED_TO,IN_DONT_FOLLOW,IN_ONLYDIR.</para>
<programlisting> &lt;inotify&gt;
&lt;event id="MOVED_TO"/&gt;
&lt;event id="DELETE"/&gt;
&lt;/inotify&gt;</programlisting>
&lt;option text=&quot;-lt%r&quot;/&gt;
&lt;option text=&quot;--delete&quot;/&gt;
&lt;exclude-file/&gt;
@ -132,8 +138,8 @@ man(1), man(7), http://www.tldp.org/HOWTO/Man-Page/
<refsect2 id="directory">
<title>DIRECTORIES</title>
<para>With <option>&lt;directory&gt;</option> nodes arbitrarily many sources to be watched can be specified. Within a &lt;directory&gt; entry you can again specify a <option>&lt;binary&gt;</option>, <option>&lt;exclude-from&gt;</option> or a <option>&lt;callopt&gt;</option> node which will override global settings just for this source. See SETTINGS for details on this options.</para>
<para> The mandatory <option>&lt;source&gt;</option> node specifies with the parameter &quot;path&quot; the directory to watch and sync. (once in a while something is mandatory. Also at least one <option>&lt;target;&gt;</option> node has to specified where to sync to. This has to be a format accepted by rsync.</para>
+ <para>With <option>&lt;directory&gt;</option> nodes arbitrarily many sources to be watched can be specified. Within a &lt;directory&gt; entry you can again specify a <option>&lt;binary&gt;</option>, <option>&lt;exclude-from&gt;</option>, <option>&lt;callopt&gt;</option> or a <option>&lt;inotify&gt;</option> node which will override global settings just for this source. See SETTINGS for details on this options.</para>
+ <para> The mandatory <option>&lt;source&gt;</option> node specifies with the paramater &quot;path&quot; the directory to watch and sync. (once in a while something is mandatory. Also at least one <option>&lt;target;&gt;</option> node has to specified where to sync to. This has to be a format accepted by rsync.</para>
<programlisting> &lt;directory&gt;
&lt;source path=&quot;/absolute/path/to/source&quot;/&gt;
&lt;target path=&quot;desthost::module/&quot;/&gt;

123
lsyncd.c
View File

@ -59,7 +59,10 @@
*/
#define DEFAULT_BINARY "/usr/bin/rsync"
#define DEFAULT_CONF_FILENAME "/etc/lsyncd.conf.xml"
const uint32_t standard_event_mask =
IN_ATTRIB | IN_CLOSE_WRITE | IN_CREATE |
IN_DELETE | IN_DELETE_SELF | IN_MOVED_FROM |
IN_MOVED_TO | IN_DONT_FOLLOW | IN_ONLYDIR;
/**
* Macros to compare times() values
* (borrowed from linux/jiffies.h)
@ -168,6 +171,11 @@ struct dir_conf {
*/
struct call_option * callopts;
/**
* bitmask of inotify events to watch (defaults to global default setting)
*/
uint32_t event_mask;
/**
* the exclude-file to pass to rsync (defaults to global default setting)
* TODO, Currently ignored!
@ -284,6 +292,11 @@ struct global_options {
* Global Option: this binary is used if no other specified in dir_conf.
*/
char *default_binary;
/**
* Global Option: default bitmask of inotify events to react upon.
*/
uint32_t default_event_mask;
/**
* Global Option: default exclude file
@ -832,6 +845,8 @@ reset_options(struct global_options *opts) {
s_free(opts->default_binary);
}
opts->default_binary = DEFAULT_BINARY;
opts->default_event_mask = standard_event_mask;
if (opts->default_exclude_file) {
s_free(opts->default_exclude_file);
@ -1185,7 +1200,7 @@ action(const struct global_options *opts,
/**
* Adds a directory to watch.
*
* @param log logging information
* @param opts global options
* @param watches the vector of watches
* @param inotify_fd inotify file descriptor
* @param pathname the absolute path of the directory to watch
@ -1196,7 +1211,7 @@ action(const struct global_options *opts,
* @return the watches of the new dir, NULL on error
*/
struct watch *
add_watch(const struct log *log,
add_watch(const struct global_options *opts,
struct watch_vector *watches,
int inotify_fd,
char const *pathname,
@ -1204,14 +1219,13 @@ add_watch(const struct log *log,
struct watch *parent,
struct dir_conf *dir_conf)
{
int wd; // kernels inotify descriptor
int wi; // index to insert this watch into the watch vector
struct watch *w; // the new watch
const struct log *log = &opts->log; // loginfo shortcut
int wd; // kernels inotify descriptor
int wi; // index to insert this watch into the watch vector
struct watch *w; // the new watch
wd = inotify_add_watch(inotify_fd, pathname,
IN_ATTRIB | IN_CLOSE_WRITE | IN_CREATE |
IN_DELETE | IN_DELETE_SELF | IN_MOVED_FROM |
IN_MOVED_TO | IN_DONT_FOLLOW | IN_ONLYDIR);
wd = inotify_add_watch(inotify_fd, pathname,
dir_conf->event_mask ? dir_conf->event_mask : opts->default_event_mask);
if (wd == -1) {
printlogf(log, ERROR, "Cannot add watch %s (%d:%s)",
@ -1409,6 +1423,30 @@ delay_or_act_dir(const struct global_options *opts,
}
}
/**
* Looks up the inotify event mask for the specified event text.
*
* @param text the name of the event to look up
*
* @return the inotify event mask or 0 if the mask name is unknown.
*/
int
event_text_to_mask(char * text)
{
int mask = 0;
struct inotify_mask_text *p;
for (p = mask_texts; p->mask; p++) {
if (!strcmp(p->text, text)) {
mask = p->mask;
break;
}
}
return mask;
}
/**
* Adds a directory including all subdirectories to watch.
* Puts the directory with all subdirectories on the delay FIFO.
@ -1460,7 +1498,7 @@ add_dirwatch(const struct global_options *opts,
}
// watch this directory
w = add_watch(log, watches, inotify_fd, pathname, dirname, parent, dir_conf);
w = add_watch(opts, watches, inotify_fd, pathname, dirname, parent, dir_conf);
if (!w) {
return NULL;
}
@ -1975,6 +2013,44 @@ parse_callopts(struct global_options *opts, xmlNodePtr node) {
return asw;
}
/**
* Parses <inotify>
*/
uint32_t
parse_inotify(xmlNodePtr node) {
xmlNodePtr dnode;
xmlChar *xc;
uint32_t mask = 0;
int id = 0;
for (dnode = node->children; dnode; dnode = dnode->next) {
if (dnode->type != XML_ELEMENT_NODE) {
continue;
}
if (!xmlStrcmp(dnode->name, BAD_CAST "event")) {
xc = xmlGetProp(dnode, BAD_CAST "id");
if (xc == NULL) {
printlogf(NULL, ERROR, "error in config file: attribute id missing from <event>\n");
exit(LSYNCD_BADCONFIGFILE);
}
id = event_text_to_mask((char*) xc);
if (!id) {
printlogf(NULL, ERROR, "error in config file: attribute id of <event>: \"%s\" not known.\n", (char*) xc);
exit(LSYNCD_BADCONFIGFILE);
}
mask |= id;
} else {
printlogf(NULL, ERROR, "error in config file: unknown node in <inotify> \"%s\"\n", dnode->name);
exit(LSYNCD_BADCONFIGFILE);
}
}
if (!mask) {
printlogf(NULL, ERROR, "error in config file: no valid <event> node in <inotify>\n");
exit(LSYNCD_BADCONFIGFILE);
}
return mask;
}
/**
* Parses <diretory>
*/
@ -2013,6 +2089,12 @@ parse_directory(struct global_options *opts, xmlNodePtr node) {
terminate(NULL, LSYNCD_BADCONFIGFILE);
}
dc->binary = s_strdup(NULL, (char *) xc, "xml binary");
} else if (!xmlStrcmp(dnode->name, BAD_CAST "callopts")) {
if (dc->callopts) {
printlogf(NULL, ERROR, "error in config file: there is more than one <callopts> in a <directory>\n");
terminate(NULL, LSYNCD_BADCONFIGFILE);
}
dc->callopts = parse_callopts(opts, dnode);
} else if (!xmlStrcmp(dnode->name, BAD_CAST "exclude-from")) {
xc = xmlGetProp(dnode, BAD_CAST "filename");
if (xc == NULL) {
@ -2020,14 +2102,13 @@ parse_directory(struct global_options *opts, xmlNodePtr node) {
terminate(NULL, LSYNCD_BADCONFIGFILE);
}
dc->exclude_file = s_strdup(NULL, (char *) xc, "xml exclude");
} else if (!xmlStrcmp(dnode->name, BAD_CAST "callopts")) {
if (dc->callopts) {
printlogf(NULL, ERROR, "error in config file: there is more than one <callopts> in a <directory>\n");
terminate(NULL, LSYNCD_BADCONFIGFILE);
}
dc->callopts = parse_callopts(opts, dnode);
} else if (!xmlStrcmp(dnode->name, BAD_CAST "inotify")) {
if (dc->event_mask) {
fprintf(stderr, "error in config file: there is more than one <inotify> in a <directory>\n");
exit(LSYNCD_BADCONFIGFILE);
}
dc->event_mask = parse_inotify(dnode);
} else {
// TODO missing sourcespecific exclude files?
printlogf(NULL, ERROR, "error in config file: unknown node in <directory> \"%s\"\n", dnode->name);
terminate(NULL, LSYNCD_BADCONFIGFILE);
}
@ -2082,6 +2163,12 @@ parse_settings(struct global_options *opts, xmlNodePtr node) {
terminate(NULL, LSYNCD_BADCONFIGFILE);
}
opts->default_exclude_file = s_strdup(NULL, (char *) xc, "xml default-exclude-file");
} else if (!xmlStrcmp(snode->name, BAD_CAST "inotify")) {
if (opts->default_event_mask) {
printlogf(NULL, ERROR, "error in config file: there is more than one <inotify> in a <directory>\n");
exit(LSYNCD_BADCONFIGFILE);
}
opts->default_event_mask = parse_inotify(snode);
} else if (!xmlStrcmp(snode->name, BAD_CAST "logfile")) {
xc = xmlGetProp(snode, BAD_CAST "filename");
if (xc == NULL) {