[Reconnoiter-devel] [reconnoiter commit] Reconnoiter branch, shatter, created. 249cc4066ac63ea5858d5c1e1644865d158ed6a4
git at labs.omniti.com
git at labs.omniti.com
Tue Nov 29 17:10:28 EST 2011
Pushed by: jesus
The branch, shatter has been created
at 249cc4066ac63ea5858d5c1e1644865d158ed6a4 (commit)
Log:
commit 249cc4066ac63ea5858d5c1e1644865d158ed6a4
Author: Theo Schlossnagle <jesus at omniti.com>
Date: Tue Nov 29 17:10:08 2011 -0500
add a notify_only option to feeds that makes noit configs blank (just as a notification that a change occurred)
diff --git a/src/noit_conf.c b/src/noit_conf.c
index 4a976f0..5b31327 100644
--- a/src/noit_conf.c
+++ b/src/noit_conf.c
@@ -1251,12 +1251,24 @@ noit_conf_write_log() {
xmlOutputBufferPtr out;
xmlCharEncodingHandlerPtr enc;
struct config_line_vstr *clv;
+ noit_boolean notify_only = noit_false;
+ const char *v;
SETUP_LOG(config, return -1);
+ v = noit_log_stream_get_property(config_log, "notify_only");
+ if(v && !strcmp(v, "on")) notify_only = noit_true;
/* We know we haven't changed */
if(last_write_gen == __config_gen) return 0;
-
gettimeofday(&__now, NULL);
+
+ if(notify_only) {
+ noitL(config_log, "n\t%lu.%03lu\t%d\t\n",
+ (unsigned long int)__now.tv_sec,
+ (unsigned long int)__now.tv_usec / 1000UL, 0);
+ last_write_gen = __config_gen;
+ return 0;
+ }
+
clv = calloc(1, sizeof(*clv));
clv->target = CONFIG_B64;
enc = xmlGetCharEncodingHandler(XML_CHAR_ENCODING_UTF8);
commit 8e9cf57ebf8fd9d4375a893d47cef1aaecce0662
Author: Theo Schlossnagle <jesus at omniti.com>
Date: Tue Nov 29 16:26:35 2011 -0500
on-disk backing store implementation
diff --git a/src/noit_check_rest.c b/src/noit_check_rest.c
index ad18060..93e493f 100644
--- a/src/noit_check_rest.c
+++ b/src/noit_check_rest.c
@@ -466,6 +466,7 @@ rest_delete_check(noit_http_rest_closure_t *restc,
/* delete this here */
noit_poller_deschedule(check->checkid);
+ CONF_REMOVE(node);
xmlUnlinkNode(node);
xmlFreeNode(node);
if(noit_conf_write_file(NULL) != 0)
diff --git a/src/noit_conf.c b/src/noit_conf.c
index 6ae7de8..4a976f0 100644
--- a/src/noit_conf.c
+++ b/src/noit_conf.c
@@ -35,6 +35,7 @@
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
+#include <dirent.h>
#include <errno.h>
#include <assert.h>
#include <libxml/parser.h>
@@ -45,6 +46,7 @@
#include "noit_conf.h"
#include "noit_check.h"
#include "noit_console.h"
+#include "noit_xml.h"
#include "utils/noit_hash.h"
#include "utils/noit_log.h"
#include "utils/noit_b64.h"
@@ -62,12 +64,28 @@ static noit_log_stream_t xml_debug = NULL;
static noit_hash_table _tmp_config = NOIT_HASH_EMPTY;
static xmlDocPtr master_config = NULL;
static int config_include_cnt = -1;
+static int backingstore_include_cnt = -1;
+
static struct {
xmlNodePtr insertion_point;
xmlNodePtr old_children;
xmlDocPtr doc;
xmlNodePtr root;
-} *config_include_nodes = NULL;
+} *config_include_nodes = NULL,
+ *backingstore_include_nodes = NULL;
+
+typedef struct noit_xml_userdata {
+ char *name;
+ char *path;
+ u_int64_t dirty_time;
+ struct noit_xml_userdata *freelist;
+} noit_xml_userdata_t;
+
+static noit_xml_userdata_t *backingstore_freelist = NULL;
+static u_int64_t last_config_flush = 0;
+
+#define is_stopnode_name(n) ((n) && (!strcmp((char *)(n), "check") || !strcmp((char *)(n), "config")))
+#define is_stopnode(node) ((node) && is_stopnode_name((node)->name))
static char *root_node_name = NULL;
static char master_config_file[PATH_MAX] = "";
@@ -80,6 +98,7 @@ static xmlXPathContextPtr xpath_ctxt = NULL;
static u_int32_t __config_gen = 0;
static u_int32_t __config_coalesce = 0;
static u_int32_t __config_coalesce_time = 0;
+static u_int64_t max_gen_count = 0;
void noit_conf_coalesce_changes(u_int32_t seconds) {
__config_coalesce_time = seconds;
}
@@ -95,6 +114,13 @@ struct recurrent_journaler {
int (*journal_config)(void *);
void *jc_closure;
};
+
+static void
+noit_xml_userdata_free(noit_xml_userdata_t *n) {
+ if(n->name) free(n->name);
+ if(n->path) free(n->path);
+}
+
static int
noit_conf_watch_config_and_journal(eventer_t e, int mask, void *closure,
struct timeval *now) {
@@ -238,6 +264,24 @@ noit_conf_magic_separate(xmlDocPtr doc) {
}
config_include_nodes = NULL;
config_include_cnt = -1;
+
+ if(backingstore_include_nodes) {
+ int i;
+ for(i=0; i<backingstore_include_cnt; i++) {
+ if(backingstore_include_nodes[i].doc) {
+ xmlNodePtr n;
+ for(n=backingstore_include_nodes[i].insertion_point->children;
+ n; n = n->next)
+ n->parent = backingstore_include_nodes[i].root;
+ backingstore_include_nodes[i].insertion_point->children =
+ backingstore_include_nodes[i].old_children;
+ xmlFreeDoc(backingstore_include_nodes[i].doc);
+ }
+ }
+ free(backingstore_include_nodes);
+ }
+ backingstore_include_nodes = NULL;
+ backingstore_include_cnt = -1;
}
void
noit_conf_kansas_city_shuffle_redo(xmlDocPtr doc) {
@@ -271,6 +315,269 @@ noit_conf_kansas_city_shuffle_undo(xmlDocPtr doc) {
}
}
}
+static u_int64_t
+usec_now() {
+ u_int64_t usec;
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ usec = tv.tv_sec * 1000000UL;
+ usec += tv.tv_usec;
+ return usec;
+}
+void
+noit_conf_backingstore_remove(noit_conf_section_t vnode) {
+ xmlNodePtr node = vnode;
+ noit_xml_userdata_t *subctx = node->_private;
+ if(subctx) {
+ noitL(noit_debug, "marking %s for removal\n", subctx->path);
+ if(!backingstore_freelist) backingstore_freelist = subctx;
+ else {
+ noit_xml_userdata_t *fl = backingstore_freelist;
+ while(fl->freelist) fl = fl->freelist;
+ fl->freelist = subctx;
+ }
+ node->_private = NULL;
+ }
+ /* If we're deleted, we'll mark the parent as dirty */
+ if(node->parent) noit_conf_backingstore_dirty(node->parent);
+}
+void
+noit_conf_backingstore_dirty(noit_conf_section_t vnode) {
+ xmlNodePtr node = vnode;
+ noit_xml_userdata_t *subctx = node->_private;
+ if(subctx) {
+ subctx->dirty_time = usec_now();
+ return;
+ }
+ if(node->parent) noit_conf_backingstore_dirty(node->parent);
+}
+int
+noit_conf_backingstore_write(noit_xml_userdata_t *ctx, noit_boolean skip,
+ xmlAttrPtr attrs, xmlNodePtr node) {
+ int failure = 0;
+ char newpath[PATH_MAX];
+ xmlNodePtr n;
+ snprintf(newpath, sizeof(newpath), "%s/.attrs", ctx->path);
+ if(attrs) {
+ xmlDocPtr tmpdoc;
+ xmlNodePtr tmpnode;
+ noitL(noit_debug, " **> %s\n", newpath);
+ tmpdoc = xmlNewDoc((xmlChar *)"1.0");
+ tmpnode = xmlNewNode(NULL, ctx->name ? (xmlChar *)ctx->name : (xmlChar *)"stub");
+ xmlDocSetRootElement(tmpdoc, tmpnode);
+ tmpnode->properties = attrs;
+ failure = noit_xmlSaveToFile(tmpdoc, newpath);
+ tmpnode->properties = NULL;
+ xmlFreeDoc(tmpdoc);
+ if(failure) return -1;
+ }
+ else if(!skip) {
+ unlink(newpath);
+ }
+ for(n = node; n; n = n->next) {
+ int leaf;
+ noit_xml_userdata_t *subctx;
+ subctx = n->_private;
+ leaf = is_stopnode(n);
+ if(!subctx) { /* This has never been written out */
+ subctx = calloc(1, sizeof(*subctx));
+ subctx->name = strdup((char *)n->name);
+ snprintf(newpath, sizeof(newpath), "%s/%s#%llu", ctx->path, n->name, ++max_gen_count);
+ if(leaf) strlcat(newpath, ".xml", sizeof(newpath));
+ subctx->path = strdup(newpath);
+ subctx->dirty_time = usec_now();
+ n->_private = subctx;
+ noitL(noit_debug, " !!> %s\n", subctx->path);
+ }
+ if(leaf) {
+ xmlDocPtr tmpdoc;
+ xmlNodePtr tmpnode;
+ if(subctx->dirty_time > last_config_flush) {
+ tmpdoc = xmlNewDoc((xmlChar *)"1.0");
+ tmpnode = xmlNewNode(NULL, n->name);
+ xmlDocSetRootElement(tmpdoc, tmpnode);
+ tmpnode->properties = n->properties;
+ tmpnode->children = n->children;
+ failure = noit_xmlSaveToFile(tmpdoc, subctx->path);
+ tmpnode->properties = NULL;
+ tmpnode->children = NULL;
+ xmlFreeDoc(tmpdoc);
+ noitL(noit_debug, " ==> %s\n", subctx->path);
+ if(failure) return -1;
+ }
+ }
+ else {
+ noit_boolean skip_attrs;
+ skip_attrs = leaf || (subctx->dirty_time <= last_config_flush);
+ noitL(noit_debug, " --> %s\n", subctx->path);
+ if(noit_conf_backingstore_write(subctx, skip_attrs, skip_attrs ? NULL : n->properties, n->children))
+ return -1;
+ }
+ }
+ return 0;
+}
+void
+noit_conf_shatter_write(xmlDocPtr doc) {
+ if(backingstore_freelist) {
+ noit_xml_userdata_t *fl, *last;
+ for(fl = backingstore_freelist; fl; ) {
+ last = fl;
+ fl = fl->freelist;
+ /* If it is a file, we'll unlink it, otherwise,
+ * we need to delete the attributes and the directory.
+ */
+ if(unlink(last->path)) {
+ char attrpath[PATH_MAX];
+ snprintf(attrpath, sizeof(attrpath), "%s/.attrs", last->path);
+ unlink(attrpath);
+ if(rmdir(last->path) && errno != ENOENT) {
+ /* This shouldn't happen, but if it does we risk
+ * leaving a mess. Don't do that.
+ */
+ noitL(noit_error, "backingstore mess %s: %s\n",
+ last->path, strerror(errno));
+ }
+ }
+ noit_xml_userdata_free(last);
+ }
+ backingstore_freelist = NULL;
+ }
+ if(backingstore_include_nodes) {
+ int i;
+ for(i=0; i<backingstore_include_cnt; i++) {
+ if(backingstore_include_nodes[i].doc) {
+ xmlNodePtr n;
+ noit_xml_userdata_t *what = backingstore_include_nodes[i].doc->_private;
+
+ for(n=backingstore_include_nodes[i].insertion_point->children;
+ n; n = n->next)
+ n->parent = backingstore_include_nodes[i].root;
+ backingstore_include_nodes[i].insertion_point->children =
+ backingstore_include_nodes[i].old_children;
+ noit_conf_backingstore_write(what, noit_false, NULL, backingstore_include_nodes[i].root->children);
+ }
+ }
+ last_config_flush = usec_now();
+ }
+}
+void
+noit_conf_shatter_postwrite(xmlDocPtr doc) {
+ if(backingstore_include_nodes) {
+ int i;
+ for(i=0; i<backingstore_include_cnt; i++) {
+ if(backingstore_include_nodes[i].doc) {
+ xmlNodePtr n;
+ backingstore_include_nodes[i].insertion_point->children =
+ backingstore_include_nodes[i].root->children;
+ for(n=backingstore_include_nodes[i].insertion_point->children;
+ n; n = n->next)
+ n->parent = backingstore_include_nodes[i].insertion_point;
+ }
+ }
+ }
+}
+
+int
+noit_conf_read_into_node(xmlNodePtr node, const char *path) {
+ DIR *dirroot;
+ struct dirent *de, *entry;
+ char filepath[PATH_MAX];
+ xmlDocPtr doc;
+ xmlNodePtr root = NULL;
+ xmlAttrPtr a;
+ struct stat sb;
+ int size, rv;
+
+ noitL(noit_debug, "read backing store: %s\n", path);
+ snprintf(filepath, sizeof(filepath), "%s/.attrs", path);
+ while((rv = stat(filepath, &sb)) < 0 && errno == EINTR);
+ if(rv == 0) {
+ doc = xmlParseFile(filepath);
+ if(doc) root = xmlDocGetRootElement(doc);
+ if(doc && root) {
+ node->properties = root->properties;
+ for(a = node->properties; a; a = a->next) {
+ a->parent = node;
+ a->doc = node->doc;
+ }
+ root->properties = NULL;
+ xmlFreeDoc(doc);
+ doc = NULL;
+ }
+ }
+#ifdef _PC_NAME_MAX
+ size = pathconf(path, _PC_NAME_MAX);
+#endif
+ size = MAX(size, PATH_MAX + 128);
+ de = alloca(size);
+ dirroot = opendir(path);
+ if(!dirroot) return -1;
+ while(portable_readdir_r(dirroot, de, &entry) == 0 && entry != NULL) {
+ noit_xml_userdata_t *udata;
+ char name[PATH_MAX];
+ char *sep;
+ xmlNodePtr child;
+ u_int64_t gen;
+
+ sep = strchr(entry->d_name, '#');
+ if(!sep) continue;
+ snprintf(filepath, sizeof(filepath), "%s/%s", path, entry->d_name);
+ while((rv = stat(filepath, &sb)) < 0 && errno == EINTR);
+ if(rv == 0) {
+ strlcpy(name, entry->d_name, sizeof(name));
+ name[sep - entry->d_name] = '\0';
+ gen = strtoull(sep+1, NULL, 10);
+ if(gen > max_gen_count) max_gen_count = gen;
+
+ if(S_ISDIR(sb.st_mode)) {
+ noitL(noit_debug, "<DIR< %s\n", entry->d_name);
+ child = xmlNewNode(NULL, (xmlChar *)name);
+ noit_conf_read_into_node(child, filepath);
+ udata = calloc(1, sizeof(*udata));
+ udata->name = strdup(name);
+ udata->path = strdup(filepath);
+ child->_private = udata;
+ xmlAddChild(node, child);
+ }
+ else if(S_ISREG(sb.st_mode)) {
+ xmlDocPtr cdoc;
+ xmlNodePtr cnode = NULL;
+ noitL(noit_debug, "<FILE< %s\n", entry->d_name);
+ cdoc = xmlParseFile(filepath);
+ if(cdoc) {
+ cnode = xmlDocGetRootElement(cdoc);
+ xmlDocSetRootElement(cdoc, xmlNewNode(NULL, (xmlChar *)"dummy"));
+ if(cnode) {
+ udata = calloc(1, sizeof(*udata));
+ udata->name = strdup(name);
+ udata->path = strdup(filepath);
+ cnode->_private = udata;
+ xmlAddChild(node, cnode);
+ }
+ xmlFreeDoc(cdoc);
+ }
+ }
+ }
+ }
+ closedir(dirroot);
+ return 0;
+}
+
+xmlDocPtr
+noit_conf_read_backing_store(const char *path) {
+ xmlDocPtr doc;
+ xmlNodePtr root;
+ noit_xml_userdata_t *what;
+
+ doc = xmlNewDoc((xmlChar *)"1.0");
+ what = calloc(1, sizeof(*what));
+ what->path = strdup(path);
+ doc->_private = what;
+ root = xmlNewNode(NULL, (xmlChar *)"stub");
+ xmlDocSetRootElement(doc, root);
+ noit_conf_read_into_node(root, path);
+ return doc;
+}
int
noit_conf_magic_mix(const char *parentfile, xmlDocPtr doc) {
xmlXPathContextPtr mix_ctxt = NULL;
@@ -279,9 +586,73 @@ noit_conf_magic_mix(const char *parentfile, xmlDocPtr doc) {
int i, cnt, rv = 0;
assert(config_include_cnt == -1);
+ assert(backingstore_include_cnt == -1);
- config_include_cnt = 0;
+ backingstore_include_cnt = 0;
mix_ctxt = xmlXPathNewContext(doc);
+ pobj = xmlXPathEval((xmlChar *)"//*[@backingstore]", mix_ctxt);
+ if(!pobj) goto includes;
+ if(pobj->type != XPATH_NODESET) goto includes;
+ if(xmlXPathNodeSetIsEmpty(pobj->nodesetval)) goto includes;
+ cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
+ if(cnt > 0)
+ backingstore_include_nodes = calloc(cnt, sizeof(*backingstore_include_nodes));
+ for(i=0; i<cnt; i++) {
+ char *path, *infile;
+ node = xmlXPathNodeSetItem(pobj->nodesetval, i);
+ path = (char *)xmlGetProp(node, (xmlChar *)"backingstore");
+ if(!path) continue;
+ if(*path == '/') infile = strdup(path);
+ else {
+ char *cp;
+ infile = malloc(PATH_MAX);
+ strlcpy(infile, parentfile, PATH_MAX);
+ for(cp = infile + strlen(infile) - 1; cp > infile; cp--) {
+ if(*cp == '/') { *cp = '\0'; break; }
+ else *cp = '\0';
+ }
+ strlcat(infile, "/", PATH_MAX);
+ strlcat(infile, path, PATH_MAX);
+ }
+ xmlFree(path);
+ backingstore_include_nodes[i].doc = noit_conf_read_backing_store(infile);
+ if(backingstore_include_nodes[i].doc) {
+ xmlNodePtr n, lchild;
+ backingstore_include_nodes[i].insertion_point = node;
+ backingstore_include_nodes[i].root = xmlDocGetRootElement(backingstore_include_nodes[i].doc);
+ /* for backing store, they are permanently reattached under the backing store.
+ * so for any children, we need to glue them into the new parent document.
+ */
+ lchild = backingstore_include_nodes[i].root->children;
+ while(lchild && lchild->next) lchild = lchild->next;
+ if(lchild) {
+ lchild->next = node->children;
+ if(node->children) node->children->prev = lchild;
+ }
+ else
+ backingstore_include_nodes[i].root->children = node->children;
+ for(n=node->children; n; n = n->next) {
+ n->parent = backingstore_include_nodes[i].root; /* this gets mapped right back, just for clarity */
+ n->doc = backingstore_include_nodes[i].doc;
+ }
+ backingstore_include_nodes[i].old_children = NULL;
+ node->children = backingstore_include_nodes[i].root->children;
+ for(n=node->children; n; n = n->next)
+ n->parent = backingstore_include_nodes[i].insertion_point;
+ }
+ else {
+ noitL(noit_error, "Could not load: '%s'\n", infile);
+ rv = -1;
+ }
+ free(infile);
+ }
+ mix_ctxt = xmlXPathNewContext(doc);
+ backingstore_include_cnt = cnt;
+ noitL(noit_debug, "Processed %d backing stores.\n", backingstore_include_cnt);
+ if(pobj) xmlXPathFreeObject(pobj);
+
+ includes:
+ config_include_cnt = 0;
pobj = xmlXPathEval((xmlChar *)"//include[@file]", mix_ctxt);
if(!pobj) goto out;
if(pobj->type != XPATH_NODESET) goto out;
@@ -825,7 +1196,9 @@ noit_conf_write_file(char **err) {
return -1;
}
noit_conf_kansas_city_shuffle_undo(master_config);
+ noit_conf_shatter_write(master_config);
len = xmlSaveFormatFileTo(out, master_config, "utf8", 1);
+ noit_conf_shatter_postwrite(master_config);
noit_conf_kansas_city_shuffle_redo(master_config);
close(fd);
if(len <= 0) {
@@ -1190,6 +1563,7 @@ noit_console_config_section(noit_console_closure_t ncct,
}
if(delete) {
node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, 0);
+ CONF_REMOVE(node);
xmlUnlinkNode(node);
noit_conf_mark_changed();
return 0;
diff --git a/src/noit_conf.h b/src/noit_conf.h
index 9d6fd88..414056b 100644
--- a/src/noit_conf.h
+++ b/src/noit_conf.h
@@ -129,6 +129,18 @@ API_EXPORT(int)
API_EXPORT(void) noit_conf_log_init(const char *toplevel);
API_EXPORT(int) noit_conf_log_init_rotate(const char *, noit_boolean);
+API_EXPORT(void) noit_conf_backingstore_remove(noit_conf_section_t node);
+API_EXPORT(void) noit_conf_backingstore_dirty(noit_conf_section_t node);
+
+#define CONF_REMOVE(n) do { \
+ noit_conf_backingstore_remove(n); \
+} while(0)
+
+#define CONF_DIRTY(n) do { \
+ noit_conf_backingstore_dirty(n); \
+ noit_conf_mark_changed(); \
+} while(0)
+
#define EXPOSE_CHECKER(name) \
API_EXPORT(pcre *) noit_conf_get_valid_##name##_checker()
#define DECLARE_CHECKER(name) \
diff --git a/src/noit_conf_checks.c b/src/noit_conf_checks.c
index c748111..5e571c4 100644
--- a/src/noit_conf_checks.c
+++ b/src/noit_conf_checks.c
@@ -172,6 +172,7 @@ noit_config_check_update_attrs(xmlNodePtr node, int argc, char **argv) {
xmlUnsetProp(node, (xmlChar *)attrinfo->name);
if(val)
xmlSetProp(node, (xmlChar *)attrinfo->name, (xmlChar *)val);
+ CONF_DIRTY(node);
noit_conf_mark_changed();
}
return error;
@@ -211,6 +212,7 @@ noit_conf_mkcheck_under(const char *ppath, int argc, char **argv, uuid_t out) {
xmlUnlinkNode(newnode);
}
else {
+ CONF_DIRTY(newnode);
noit_conf_mark_changed();
rv = 0;
}
@@ -585,9 +587,11 @@ noit_console_config_nocheck(noit_console_closure_t ncct,
int j;
for(j=1;j<argc;j++)
xmlUnsetProp(node, (xmlChar *)argv[j]);
+ CONF_DIRTY(node);
} else {
nc_printf(ncct, "descheduling %s\n", uuid_conf);
noit_poller_deschedule(checkid);
+ CONF_REMOVE(node);
xmlUnlinkNode(node);
}
noit_conf_mark_changed();
@@ -903,6 +907,7 @@ replace_config(noit_console_closure_t ncct,
if(xmlXPathNodeSetGetLength(pobj->nodesetval) > 0) {
xmlNodePtr toremove;
toremove = xmlXPathNodeSetItem(pobj->nodesetval, 0);
+ CONF_REMOVE(toremove);
xmlUnlinkNode(toremove);
}
/* TODO: if there are no more children of config, remove config? */
@@ -933,6 +938,7 @@ replace_config(noit_console_closure_t ncct,
assert(confignode);
/* Now we create a child */
xmlNewChild(confignode, NULL, (xmlChar *)name, (xmlChar *)value);
+ CONF_DIRTY(confignode);
}
noit_conf_mark_changed();
rv = 0;
@@ -1005,6 +1011,7 @@ replace_attr(noit_console_closure_t ncct,
xmlUnsetProp(node, (xmlChar *)attrinfo->name);
if(value)
xmlSetProp(node, (xmlChar *)attrinfo->name, (xmlChar *)value);
+ CONF_DIRTY(node);
noit_conf_mark_changed();
rv = 0;
out:
diff --git a/src/noit_filters_rest.c b/src/noit_filters_rest.c
index c257a3b..469e06e 100644
--- a/src/noit_filters_rest.c
+++ b/src/noit_filters_rest.c
@@ -147,6 +147,7 @@ rest_delete_filter(noit_http_rest_closure_t *restc,
node = noit_conf_get_section(NULL, xpath);
if(!node) goto not_found;
if(noit_filter_remove(node) == 0) goto not_found;
+ CONF_REMOVE(node);
xmlUnlinkNode(node);
xmlFreeNode(node);
diff --git a/src/noit_xml.c b/src/noit_xml.c
index 90b37e8..26832b3 100644
--- a/src/noit_xml.c
+++ b/src/noit_xml.c
@@ -30,7 +30,13 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include "noit_defines.h"
#include "noit_xml.h"
+#include "utils/noit_log.h"
+#include "utils/noit_mkdir.h"
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
#include <assert.h>
struct noit_xml_buffer_ptr {
@@ -84,3 +90,62 @@ noit_xmlSaveToBuffer(xmlDocPtr doc) {
return buf.buff;
}
+int
+noit_xmlSaveToFile(xmlDocPtr doc, const char *filename) {
+ int rv = -1, fd, have_backup = 0, once;
+ char tmpfile[PATH_MAX], bakfile[PATH_MAX];
+ xmlOutputBufferPtr out;
+ xmlCharEncodingHandlerPtr enc;
+
+ snprintf(tmpfile, sizeof(tmpfile), "%s.tmp", filename);
+ snprintf(bakfile, sizeof(bakfile), "%s.bak", filename);
+ once = 1;
+ mkbkup:
+ if(link(filename, bakfile) == 0) {
+ unlink(filename);
+ have_backup = 1;
+ }
+ else if (errno != ENOENT) {
+ if(!once) return -1;
+ once = 0;
+ if(errno == EEXIST) {
+ unlink(bakfile);
+ goto mkbkup;
+ }
+ noitL(noit_error, "Cannot create backup for %s: %s\n",
+ filename, strerror(errno));
+ return -1;
+ }
+ else {
+ noitL(noit_debug, "link(%s,%s) -> %s\n", filename, bakfile, strerror(errno));
+ }
+
+ retry:
+ fd = open(tmpfile, O_WRONLY | O_CREAT | O_EXCL, 0640);
+ if(fd < 0) {
+ if(!once) return -1;
+ once = 0;
+ if(errno == ENOENT) {
+ if(mkdir_for_file(tmpfile, 0750) == 0) goto retry;
+ }
+ if(errno == EEXIST) {
+ unlink(tmpfile);
+ goto retry;
+ }
+ return -1;
+ }
+ enc = xmlGetCharEncodingHandler(XML_CHAR_ENCODING_UTF8);
+ out = xmlOutputBufferCreateFd(fd, enc);
+ assert(out);
+ xmlSaveFormatFileTo(out, doc, "utf8", 1);
+ close(fd);
+ rv = 0;
+ if(link(tmpfile, filename)) {
+ rv = -1;
+ if(link(bakfile, filename) != 0) have_backup = 0;
+ }
+ unlink(tmpfile);
+ if(have_backup)
+ unlink(bakfile);
+ return rv;
+}
diff --git a/src/noit_xml.h b/src/noit_xml.h
index ce60003..700ac58 100644
--- a/src/noit_xml.h
+++ b/src/noit_xml.h
@@ -39,4 +39,7 @@
API_EXPORT(char *)
noit_xmlSaveToBuffer(xmlDocPtr doc);
+API_EXPORT(int)
+ noit_xmlSaveToFile(xmlDocPtr doc, const char *filename);
+
#endif
diff --git a/src/stratcon_jlog_streamer.c b/src/stratcon_jlog_streamer.c
index c82840b..3dbfe30 100644
--- a/src/stratcon_jlog_streamer.c
+++ b/src/stratcon_jlog_streamer.c
@@ -1462,6 +1462,7 @@ stratcon_remove_noit(const char *target, unsigned short port) {
free, free);
pthread_mutex_unlock(&noit_ip_by_cn_lock);
}
+ CONF_REMOVE(noit_configs[i]);
xmlUnlinkNode(noit_configs[i]);
xmlFreeNode(noit_configs[i]);
n = 0;
hooks/post-receive
--
Reconnoiter
More information about the Reconnoiter-devel
mailing list