Changeset 8e9cf57ebf8fd9d4375a893d47cef1aaecce0662

Show
Ignore:
Timestamp:
11/29/11 21:26:35 (2 years ago)
Author:
Theo Schlossnagle <jesus@omniti.com>
git-committer:
Theo Schlossnagle <jesus@omniti.com> 1322601995 -0500
git-parent:

[e09f057cc61b7872af870562a9ca11fc52860502]

git-author:
Theo Schlossnagle <jesus@omniti.com> 1322601995 -0500
Message:

on-disk backing store implementation

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • src/noit_check_rest.c

    r6033f87 r8e9cf57  
    467467  /* delete this here */ 
    468468  noit_poller_deschedule(check->checkid); 
     469  CONF_REMOVE(node); 
    469470  xmlUnlinkNode(node); 
    470471  xmlFreeNode(node); 
  • src/noit_conf.c

    r82dc7d3 r8e9cf57  
    3636#include <unistd.h> 
    3737#include <fcntl.h> 
     38#include <dirent.h> 
    3839#include <errno.h> 
    3940#include <assert.h> 
     
    4647#include "noit_check.h" 
    4748#include "noit_console.h" 
     49#include "noit_xml.h" 
    4850#include "utils/noit_hash.h" 
    4951#include "utils/noit_log.h" 
     
    6365static xmlDocPtr master_config = NULL; 
    6466static int config_include_cnt = -1; 
     67static int backingstore_include_cnt = -1; 
     68 
    6569static struct { 
    6670  xmlNodePtr insertion_point; 
     
    6872  xmlDocPtr doc; 
    6973  xmlNodePtr root; 
    70 } *config_include_nodes = NULL; 
     74} *config_include_nodes = NULL, 
     75  *backingstore_include_nodes = NULL; 
     76 
     77typedef struct noit_xml_userdata { 
     78  char       *name; 
     79  char       *path; 
     80  u_int64_t   dirty_time; 
     81  struct noit_xml_userdata *freelist; 
     82} noit_xml_userdata_t; 
     83 
     84static noit_xml_userdata_t *backingstore_freelist = NULL; 
     85static u_int64_t last_config_flush = 0; 
     86 
     87#define is_stopnode_name(n) ((n) && (!strcmp((char *)(n), "check") || !strcmp((char *)(n), "config"))) 
     88#define is_stopnode(node) ((node) && is_stopnode_name((node)->name)) 
    7189 
    7290static char *root_node_name = NULL; 
     
    8199static u_int32_t __config_coalesce = 0; 
    82100static u_int32_t __config_coalesce_time = 0; 
     101static u_int64_t max_gen_count = 0; 
    83102void noit_conf_coalesce_changes(u_int32_t seconds) { 
    84103  __config_coalesce_time = seconds; 
     
    96115  void *jc_closure; 
    97116}; 
     117 
     118static void 
     119noit_xml_userdata_free(noit_xml_userdata_t *n) { 
     120  if(n->name) free(n->name); 
     121  if(n->path) free(n->path); 
     122} 
     123 
    98124static int 
    99125noit_conf_watch_config_and_journal(eventer_t e, int mask, void *closure, 
     
    239265  config_include_nodes = NULL; 
    240266  config_include_cnt = -1; 
     267 
     268  if(backingstore_include_nodes) { 
     269    int i; 
     270    for(i=0; i<backingstore_include_cnt; i++) { 
     271      if(backingstore_include_nodes[i].doc) { 
     272        xmlNodePtr n; 
     273        for(n=backingstore_include_nodes[i].insertion_point->children; 
     274            n; n = n->next) 
     275          n->parent = backingstore_include_nodes[i].root; 
     276        backingstore_include_nodes[i].insertion_point->children = 
     277          backingstore_include_nodes[i].old_children; 
     278        xmlFreeDoc(backingstore_include_nodes[i].doc); 
     279      } 
     280    } 
     281    free(backingstore_include_nodes); 
     282  } 
     283  backingstore_include_nodes = NULL; 
     284  backingstore_include_cnt = -1; 
    241285} 
    242286void 
     
    272316  } 
    273317} 
     318static u_int64_t 
     319usec_now() { 
     320  u_int64_t usec; 
     321  struct timeval tv; 
     322  gettimeofday(&tv, NULL); 
     323  usec = tv.tv_sec * 1000000UL; 
     324  usec += tv.tv_usec; 
     325  return usec; 
     326} 
     327void 
     328noit_conf_backingstore_remove(noit_conf_section_t vnode) { 
     329  xmlNodePtr node = vnode; 
     330  noit_xml_userdata_t *subctx = node->_private; 
     331  if(subctx) { 
     332    noitL(noit_debug, "marking %s for removal\n", subctx->path); 
     333    if(!backingstore_freelist) backingstore_freelist = subctx; 
     334    else { 
     335      noit_xml_userdata_t *fl = backingstore_freelist; 
     336      while(fl->freelist) fl = fl->freelist; 
     337      fl->freelist = subctx; 
     338    } 
     339    node->_private = NULL; 
     340  } 
     341  /* If we're deleted, we'll mark the parent as dirty */ 
     342  if(node->parent) noit_conf_backingstore_dirty(node->parent); 
     343} 
     344void 
     345noit_conf_backingstore_dirty(noit_conf_section_t vnode) { 
     346  xmlNodePtr node = vnode; 
     347  noit_xml_userdata_t *subctx = node->_private; 
     348  if(subctx) { 
     349    subctx->dirty_time = usec_now(); 
     350    return; 
     351  } 
     352  if(node->parent) noit_conf_backingstore_dirty(node->parent); 
     353} 
     354int 
     355noit_conf_backingstore_write(noit_xml_userdata_t *ctx, noit_boolean skip, 
     356                             xmlAttrPtr attrs, xmlNodePtr node) { 
     357  int failure = 0; 
     358  char newpath[PATH_MAX]; 
     359  xmlNodePtr n; 
     360  snprintf(newpath, sizeof(newpath), "%s/.attrs", ctx->path); 
     361  if(attrs) { 
     362    xmlDocPtr tmpdoc; 
     363    xmlNodePtr tmpnode; 
     364    noitL(noit_debug, " **> %s\n", newpath); 
     365    tmpdoc = xmlNewDoc((xmlChar *)"1.0"); 
     366    tmpnode = xmlNewNode(NULL, ctx->name ? (xmlChar *)ctx->name : (xmlChar *)"stub"); 
     367    xmlDocSetRootElement(tmpdoc, tmpnode); 
     368    tmpnode->properties = attrs; 
     369    failure = noit_xmlSaveToFile(tmpdoc, newpath); 
     370    tmpnode->properties = NULL; 
     371    xmlFreeDoc(tmpdoc); 
     372    if(failure) return -1; 
     373  } 
     374  else if(!skip) { 
     375    unlink(newpath); 
     376  } 
     377  for(n = node; n; n = n->next) { 
     378    int leaf; 
     379    noit_xml_userdata_t *subctx; 
     380    subctx = n->_private; 
     381    leaf = is_stopnode(n); 
     382    if(!subctx) { /* This has never been written out */ 
     383      subctx = calloc(1, sizeof(*subctx)); 
     384      subctx->name = strdup((char *)n->name); 
     385      snprintf(newpath, sizeof(newpath), "%s/%s#%llu", ctx->path, n->name, ++max_gen_count); 
     386      if(leaf) strlcat(newpath, ".xml", sizeof(newpath)); 
     387      subctx->path = strdup(newpath); 
     388      subctx->dirty_time = usec_now(); 
     389      n->_private = subctx; 
     390      noitL(noit_debug, " !!> %s\n", subctx->path); 
     391    } 
     392    if(leaf) { 
     393      xmlDocPtr tmpdoc; 
     394      xmlNodePtr tmpnode; 
     395      if(subctx->dirty_time > last_config_flush) { 
     396        tmpdoc = xmlNewDoc((xmlChar *)"1.0"); 
     397        tmpnode = xmlNewNode(NULL, n->name); 
     398        xmlDocSetRootElement(tmpdoc, tmpnode); 
     399        tmpnode->properties = n->properties; 
     400        tmpnode->children = n->children; 
     401        failure = noit_xmlSaveToFile(tmpdoc, subctx->path); 
     402        tmpnode->properties = NULL; 
     403        tmpnode->children = NULL; 
     404        xmlFreeDoc(tmpdoc); 
     405        noitL(noit_debug, " ==> %s\n", subctx->path); 
     406        if(failure) return -1; 
     407      } 
     408    } 
     409    else { 
     410      noit_boolean skip_attrs; 
     411      skip_attrs = leaf || (subctx->dirty_time <= last_config_flush); 
     412      noitL(noit_debug, " --> %s\n", subctx->path); 
     413      if(noit_conf_backingstore_write(subctx, skip_attrs, skip_attrs ? NULL : n->properties, n->children)) 
     414        return -1; 
     415    } 
     416  } 
     417  return 0; 
     418} 
     419void 
     420noit_conf_shatter_write(xmlDocPtr doc) { 
     421  if(backingstore_freelist) { 
     422    noit_xml_userdata_t *fl, *last; 
     423    for(fl = backingstore_freelist; fl; ) { 
     424      last = fl; 
     425      fl = fl->freelist; 
     426      /* If it is a file, we'll unlink it, otherwise, 
     427       * we need to delete the attributes and the directory. 
     428       */ 
     429      if(unlink(last->path)) { 
     430        char attrpath[PATH_MAX]; 
     431        snprintf(attrpath, sizeof(attrpath), "%s/.attrs", last->path); 
     432        unlink(attrpath); 
     433        if(rmdir(last->path) && errno != ENOENT) { 
     434          /* This shouldn't happen, but if it does we risk 
     435           * leaving a mess. Don't do that. 
     436           */ 
     437          noitL(noit_error, "backingstore mess %s: %s\n", 
     438                last->path, strerror(errno)); 
     439        } 
     440      } 
     441      noit_xml_userdata_free(last); 
     442    } 
     443    backingstore_freelist = NULL; 
     444  } 
     445  if(backingstore_include_nodes) { 
     446    int i; 
     447    for(i=0; i<backingstore_include_cnt; i++) { 
     448      if(backingstore_include_nodes[i].doc) { 
     449        xmlNodePtr n; 
     450        noit_xml_userdata_t *what = backingstore_include_nodes[i].doc->_private; 
     451 
     452        for(n=backingstore_include_nodes[i].insertion_point->children; 
     453            n; n = n->next) 
     454          n->parent = backingstore_include_nodes[i].root; 
     455        backingstore_include_nodes[i].insertion_point->children = 
     456          backingstore_include_nodes[i].old_children; 
     457        noit_conf_backingstore_write(what, noit_false, NULL, backingstore_include_nodes[i].root->children); 
     458      } 
     459    } 
     460    last_config_flush = usec_now(); 
     461  } 
     462} 
     463void 
     464noit_conf_shatter_postwrite(xmlDocPtr doc) { 
     465  if(backingstore_include_nodes) { 
     466    int i; 
     467    for(i=0; i<backingstore_include_cnt; i++) { 
     468      if(backingstore_include_nodes[i].doc) { 
     469        xmlNodePtr n; 
     470        backingstore_include_nodes[i].insertion_point->children = 
     471          backingstore_include_nodes[i].root->children; 
     472        for(n=backingstore_include_nodes[i].insertion_point->children; 
     473            n; n = n->next) 
     474          n->parent = backingstore_include_nodes[i].insertion_point; 
     475      } 
     476    } 
     477  } 
     478} 
     479 
     480int 
     481noit_conf_read_into_node(xmlNodePtr node, const char *path) { 
     482  DIR *dirroot; 
     483  struct dirent *de, *entry; 
     484  char filepath[PATH_MAX]; 
     485  xmlDocPtr doc; 
     486  xmlNodePtr root = NULL; 
     487  xmlAttrPtr a; 
     488  struct stat sb; 
     489  int size, rv; 
     490 
     491  noitL(noit_debug, "read backing store: %s\n", path); 
     492  snprintf(filepath, sizeof(filepath), "%s/.attrs", path); 
     493  while((rv = stat(filepath, &sb)) < 0 && errno == EINTR); 
     494  if(rv == 0) { 
     495    doc = xmlParseFile(filepath); 
     496    if(doc) root = xmlDocGetRootElement(doc); 
     497    if(doc && root) { 
     498      node->properties = root->properties; 
     499      for(a = node->properties; a; a = a->next) { 
     500        a->parent = node; 
     501        a->doc = node->doc; 
     502      } 
     503      root->properties = NULL; 
     504      xmlFreeDoc(doc); 
     505      doc = NULL; 
     506    } 
     507  } 
     508#ifdef _PC_NAME_MAX 
     509  size = pathconf(path, _PC_NAME_MAX); 
     510#endif 
     511  size = MAX(size, PATH_MAX + 128); 
     512  de = alloca(size); 
     513  dirroot = opendir(path); 
     514  if(!dirroot) return -1; 
     515  while(portable_readdir_r(dirroot, de, &entry) == 0 && entry != NULL) { 
     516    noit_xml_userdata_t *udata; 
     517    char name[PATH_MAX]; 
     518    char *sep; 
     519    xmlNodePtr child; 
     520    u_int64_t gen; 
     521 
     522    sep = strchr(entry->d_name, '#'); 
     523    if(!sep) continue; 
     524    snprintf(filepath, sizeof(filepath), "%s/%s", path, entry->d_name); 
     525    while((rv = stat(filepath, &sb)) < 0 && errno == EINTR); 
     526    if(rv == 0) { 
     527      strlcpy(name, entry->d_name, sizeof(name)); 
     528      name[sep - entry->d_name] = '\0'; 
     529      gen = strtoull(sep+1, NULL, 10); 
     530      if(gen > max_gen_count) max_gen_count = gen; 
     531 
     532      if(S_ISDIR(sb.st_mode)) { 
     533        noitL(noit_debug, "<DIR< %s\n", entry->d_name); 
     534        child = xmlNewNode(NULL, (xmlChar *)name); 
     535        noit_conf_read_into_node(child, filepath); 
     536        udata = calloc(1, sizeof(*udata)); 
     537        udata->name = strdup(name); 
     538        udata->path = strdup(filepath); 
     539        child->_private = udata; 
     540        xmlAddChild(node, child); 
     541      } 
     542      else if(S_ISREG(sb.st_mode)) { 
     543        xmlDocPtr cdoc; 
     544        xmlNodePtr cnode = NULL; 
     545        noitL(noit_debug, "<FILE< %s\n", entry->d_name); 
     546        cdoc = xmlParseFile(filepath); 
     547        if(cdoc) { 
     548          cnode = xmlDocGetRootElement(cdoc); 
     549          xmlDocSetRootElement(cdoc, xmlNewNode(NULL, (xmlChar *)"dummy")); 
     550          if(cnode) { 
     551            udata = calloc(1, sizeof(*udata)); 
     552            udata->name = strdup(name); 
     553            udata->path = strdup(filepath); 
     554            cnode->_private = udata; 
     555            xmlAddChild(node, cnode); 
     556          } 
     557          xmlFreeDoc(cdoc); 
     558        } 
     559      } 
     560    } 
     561  } 
     562  closedir(dirroot); 
     563  return 0; 
     564} 
     565 
     566xmlDocPtr 
     567noit_conf_read_backing_store(const char *path) { 
     568  xmlDocPtr doc; 
     569  xmlNodePtr root; 
     570  noit_xml_userdata_t *what; 
     571 
     572  doc = xmlNewDoc((xmlChar *)"1.0"); 
     573  what = calloc(1, sizeof(*what)); 
     574  what->path = strdup(path); 
     575  doc->_private = what; 
     576  root = xmlNewNode(NULL, (xmlChar *)"stub"); 
     577  xmlDocSetRootElement(doc, root); 
     578  noit_conf_read_into_node(root, path); 
     579  return doc; 
     580} 
    274581int 
    275582noit_conf_magic_mix(const char *parentfile, xmlDocPtr doc) { 
     
    280587 
    281588  assert(config_include_cnt == -1); 
    282  
     589  assert(backingstore_include_cnt == -1); 
     590 
     591  backingstore_include_cnt = 0; 
     592  mix_ctxt = xmlXPathNewContext(doc); 
     593  pobj = xmlXPathEval((xmlChar *)"//*[@backingstore]", mix_ctxt); 
     594  if(!pobj) goto includes; 
     595  if(pobj->type != XPATH_NODESET) goto includes; 
     596  if(xmlXPathNodeSetIsEmpty(pobj->nodesetval)) goto includes; 
     597  cnt = xmlXPathNodeSetGetLength(pobj->nodesetval); 
     598  if(cnt > 0) 
     599    backingstore_include_nodes = calloc(cnt, sizeof(*backingstore_include_nodes)); 
     600  for(i=0; i<cnt; i++) { 
     601    char *path, *infile; 
     602    node = xmlXPathNodeSetItem(pobj->nodesetval, i); 
     603    path = (char *)xmlGetProp(node, (xmlChar *)"backingstore"); 
     604    if(!path) continue; 
     605    if(*path == '/') infile = strdup(path); 
     606    else { 
     607      char *cp; 
     608      infile = malloc(PATH_MAX); 
     609      strlcpy(infile, parentfile, PATH_MAX); 
     610      for(cp = infile + strlen(infile) - 1; cp > infile; cp--) { 
     611        if(*cp == '/') { *cp = '\0'; break; } 
     612        else *cp = '\0'; 
     613      } 
     614      strlcat(infile, "/", PATH_MAX); 
     615      strlcat(infile, path, PATH_MAX); 
     616    } 
     617    xmlFree(path); 
     618    backingstore_include_nodes[i].doc = noit_conf_read_backing_store(infile); 
     619    if(backingstore_include_nodes[i].doc) { 
     620      xmlNodePtr n, lchild; 
     621      backingstore_include_nodes[i].insertion_point = node; 
     622      backingstore_include_nodes[i].root = xmlDocGetRootElement(backingstore_include_nodes[i].doc); 
     623      /* for backing store, they are permanently reattached under the backing store. 
     624       * so for any children, we need to glue them into the new parent document. 
     625       */ 
     626      lchild = backingstore_include_nodes[i].root->children; 
     627      while(lchild && lchild->next) lchild = lchild->next; 
     628      if(lchild) { 
     629        lchild->next = node->children; 
     630        if(node->children) node->children->prev = lchild; 
     631      } 
     632      else 
     633        backingstore_include_nodes[i].root->children = node->children; 
     634      for(n=node->children; n; n = n->next) { 
     635        n->parent = backingstore_include_nodes[i].root; /* this gets mapped right back, just for clarity */ 
     636        n->doc = backingstore_include_nodes[i].doc; 
     637      } 
     638      backingstore_include_nodes[i].old_children = NULL; 
     639      node->children = backingstore_include_nodes[i].root->children; 
     640      for(n=node->children; n; n = n->next) 
     641        n->parent = backingstore_include_nodes[i].insertion_point; 
     642    } 
     643    else { 
     644      noitL(noit_error, "Could not load: '%s'\n", infile); 
     645      rv = -1; 
     646    } 
     647    free(infile); 
     648  } 
     649  mix_ctxt = xmlXPathNewContext(doc); 
     650  backingstore_include_cnt = cnt; 
     651  noitL(noit_debug, "Processed %d backing stores.\n", backingstore_include_cnt); 
     652  if(pobj) xmlXPathFreeObject(pobj); 
     653 
     654 includes: 
    283655  config_include_cnt = 0; 
    284   mix_ctxt = xmlXPathNewContext(doc); 
    285656  pobj = xmlXPathEval((xmlChar *)"//include[@file]", mix_ctxt); 
    286657  if(!pobj) goto out; 
     
    8261197  } 
    8271198  noit_conf_kansas_city_shuffle_undo(master_config); 
     1199  noit_conf_shatter_write(master_config); 
    8281200  len = xmlSaveFormatFileTo(out, master_config, "utf8", 1); 
     1201  noit_conf_shatter_postwrite(master_config); 
    8291202  noit_conf_kansas_city_shuffle_redo(master_config); 
    8301203  close(fd); 
     
    11911564  if(delete) { 
    11921565    node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, 0); 
     1566    CONF_REMOVE(node); 
    11931567    xmlUnlinkNode(node); 
    11941568    noit_conf_mark_changed(); 
  • src/noit_conf.h

    rdb7317d r8e9cf57  
    130130API_EXPORT(int) noit_conf_log_init_rotate(const char *, noit_boolean); 
    131131 
     132API_EXPORT(void) noit_conf_backingstore_remove(noit_conf_section_t node); 
     133API_EXPORT(void) noit_conf_backingstore_dirty(noit_conf_section_t node); 
     134 
     135#define CONF_REMOVE(n) do { \ 
     136  noit_conf_backingstore_remove(n); \ 
     137} while(0) 
     138 
     139#define CONF_DIRTY(n) do { \ 
     140 noit_conf_backingstore_dirty(n); \ 
     141 noit_conf_mark_changed(); \ 
     142} while(0) 
     143 
    132144#define EXPOSE_CHECKER(name) \ 
    133145  API_EXPORT(pcre *) noit_conf_get_valid_##name##_checker() 
  • src/noit_conf_checks.c

    r022178b r8e9cf57  
    173173    if(val) 
    174174      xmlSetProp(node, (xmlChar *)attrinfo->name, (xmlChar *)val); 
     175    CONF_DIRTY(node); 
    175176    noit_conf_mark_changed(); 
    176177  } 
     
    212213    } 
    213214    else { 
     215      CONF_DIRTY(newnode); 
    214216      noit_conf_mark_changed(); 
    215217      rv = 0; 
     
    586588        for(j=1;j<argc;j++) 
    587589          xmlUnsetProp(node, (xmlChar *)argv[j]); 
     590        CONF_DIRTY(node); 
    588591      } else { 
    589592        nc_printf(ncct, "descheduling %s\n", uuid_conf); 
    590593        noit_poller_deschedule(checkid); 
     594        CONF_REMOVE(node); 
    591595        xmlUnlinkNode(node); 
    592596      } 
     
    904908    xmlNodePtr toremove; 
    905909    toremove = xmlXPathNodeSetItem(pobj->nodesetval, 0); 
     910    CONF_REMOVE(toremove); 
    906911    xmlUnlinkNode(toremove); 
    907912  } 
     
    934939    /* Now we create a child */ 
    935940    xmlNewChild(confignode, NULL, (xmlChar *)name, (xmlChar *)value); 
     941    CONF_DIRTY(confignode); 
    936942  } 
    937943  noit_conf_mark_changed(); 
     
    10061012  if(value) 
    10071013    xmlSetProp(node, (xmlChar *)attrinfo->name, (xmlChar *)value); 
     1014  CONF_DIRTY(node); 
    10081015  noit_conf_mark_changed(); 
    10091016  rv = 0; 
  • src/noit_filters_rest.c

    r637731d r8e9cf57  
    148148  if(!node) goto not_found; 
    149149  if(noit_filter_remove(node) == 0) goto not_found; 
     150  CONF_REMOVE(node); 
    150151  xmlUnlinkNode(node); 
    151152  xmlFreeNode(node); 
  • src/noit_xml.c

    rc30a0fe r8e9cf57  
    3131 */ 
    3232 
     33#include "noit_defines.h" 
    3334#include "noit_xml.h" 
     35#include "utils/noit_log.h" 
     36#include "utils/noit_mkdir.h" 
     37#include <fcntl.h> 
     38#include <unistd.h> 
     39#include <errno.h> 
    3440#include <assert.h> 
    3541 
     
    8591} 
    8692 
     93int 
     94noit_xmlSaveToFile(xmlDocPtr doc, const char *filename) { 
     95  int rv = -1, fd, have_backup = 0, once; 
     96  char tmpfile[PATH_MAX], bakfile[PATH_MAX]; 
     97  xmlOutputBufferPtr out; 
     98  xmlCharEncodingHandlerPtr enc; 
     99 
     100  snprintf(tmpfile, sizeof(tmpfile), "%s.tmp", filename); 
     101  snprintf(bakfile, sizeof(bakfile), "%s.bak", filename); 
     102  once = 1; 
     103 mkbkup: 
     104  if(link(filename, bakfile) == 0) { 
     105    unlink(filename); 
     106    have_backup = 1; 
     107  } 
     108  else if (errno != ENOENT) { 
     109    if(!once) return -1; 
     110    once = 0; 
     111    if(errno == EEXIST) { 
     112      unlink(bakfile); 
     113      goto mkbkup; 
     114    } 
     115    noitL(noit_error, "Cannot create backup for %s: %s\n", 
     116          filename, strerror(errno)); 
     117    return -1; 
     118  } 
     119  else { 
     120    noitL(noit_debug, "link(%s,%s) -> %s\n", filename, bakfile, strerror(errno)); 
     121  } 
     122 
     123 retry: 
     124  fd = open(tmpfile, O_WRONLY | O_CREAT | O_EXCL, 0640); 
     125  if(fd < 0) { 
     126    if(!once) return -1; 
     127    once = 0; 
     128    if(errno == ENOENT) { 
     129      if(mkdir_for_file(tmpfile, 0750) == 0) goto retry; 
     130    } 
     131    if(errno == EEXIST) { 
     132      unlink(tmpfile); 
     133      goto retry; 
     134    } 
     135    return -1; 
     136  } 
     137  enc = xmlGetCharEncodingHandler(XML_CHAR_ENCODING_UTF8); 
     138  out = xmlOutputBufferCreateFd(fd, enc); 
     139  assert(out); 
     140  xmlSaveFormatFileTo(out, doc, "utf8", 1); 
     141  close(fd); 
     142  rv = 0; 
     143  if(link(tmpfile, filename)) { 
     144    rv = -1; 
     145    if(link(bakfile, filename) != 0) have_backup = 0; 
     146  } 
     147  unlink(tmpfile); 
     148  if(have_backup) 
     149    unlink(bakfile); 
     150  return rv; 
     151} 
  • src/noit_xml.h

    rea6ba41 r8e9cf57  
    4040  noit_xmlSaveToBuffer(xmlDocPtr doc); 
    4141 
     42API_EXPORT(int) 
     43  noit_xmlSaveToFile(xmlDocPtr doc, const char *filename); 
     44 
    4245#endif 
  • src/stratcon_jlog_streamer.c

    r39120ca r8e9cf57  
    14631463      pthread_mutex_unlock(&noit_ip_by_cn_lock); 
    14641464    } 
     1465    CONF_REMOVE(noit_configs[i]); 
    14651466    xmlUnlinkNode(noit_configs[i]); 
    14661467    xmlFreeNode(noit_configs[i]);