Changeset 80f47472f0d3f59e9aceccab41a0940edd7946d3
- Timestamp:
- 01/04/12 21:55:54 (6 years ago)
- git-parent:
[1a07d8a36938e3fe7306909982a2d3bdb372d002], [70a52b32620458fceed674ce5d4f8e10dd65aad5]
- Files:
-
- src/noit_check_rest.c (modified) (1 diff)
- src/noit_conf.c (modified) (12 diffs)
- src/noit_conf.h (modified) (1 diff)
- src/noit_conf_checks.c (modified) (6 diffs)
- src/noit_filters_rest.c (modified) (1 diff)
- src/noit_xml.c (modified) (2 diffs)
- src/noit_xml.h (modified) (1 diff)
- src/stratcon_jlog_streamer.c (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
src/noit_check_rest.c
rc6c11c3 r80f4747 488 488 /* delete this here */ 489 489 noit_poller_deschedule(check->checkid); 490 CONF_REMOVE(node); 490 491 xmlUnlinkNode(node); 491 492 xmlFreeNode(node); src/noit_conf.c
rc6c11c3 r80f4747 36 36 #include <unistd.h> 37 37 #include <fcntl.h> 38 #include <dirent.h> 38 39 #include <errno.h> 39 40 #include <assert.h> … … 46 47 #include "noit_check.h" 47 48 #include "noit_console.h" 49 #include "noit_xml.h" 48 50 #include "utils/noit_hash.h" 49 51 #include "utils/noit_log.h" … … 63 65 static xmlDocPtr master_config = NULL; 64 66 static int config_include_cnt = -1; 67 static int backingstore_include_cnt = -1; 68 65 69 static struct { 66 70 xmlNodePtr insertion_point; … … 68 72 xmlDocPtr doc; 69 73 xmlNodePtr root; 70 } *config_include_nodes = NULL; 74 } *config_include_nodes = NULL, 75 *backingstore_include_nodes = NULL; 76 77 typedef 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 84 static noit_xml_userdata_t *backingstore_freelist = NULL; 85 static u_int64_t last_config_flush = 0; 86 87 #define is_stopnode_name(n) ((n) && \ 88 (!strcmp((char *)(n), "check") || \ 89 !strcmp((char *)(n), "config") || \ 90 !strcmp((char *)(n), "filterset"))) 91 #define is_stopnode(node) ((node) && is_stopnode_name((node)->name)) 71 92 72 93 static char *root_node_name = NULL; … … 81 102 static u_int32_t __config_coalesce = 0; 82 103 static u_int32_t __config_coalesce_time = 0; 104 static u_int64_t max_gen_count = 0; 83 105 void noit_conf_coalesce_changes(u_int32_t seconds) { 84 106 __config_coalesce_time = seconds; … … 96 118 void *jc_closure; 97 119 }; 120 121 static void 122 noit_xml_userdata_free(noit_xml_userdata_t *n) { 123 if(n->name) free(n->name); 124 if(n->path) free(n->path); 125 } 126 98 127 static int 99 128 noit_conf_watch_config_and_journal(eventer_t e, int mask, void *closure, … … 239 268 config_include_nodes = NULL; 240 269 config_include_cnt = -1; 270 271 if(backingstore_include_nodes) { 272 int i; 273 for(i=0; i<backingstore_include_cnt; i++) { 274 if(backingstore_include_nodes[i].doc) { 275 xmlNodePtr n; 276 for(n=backingstore_include_nodes[i].insertion_point->children; 277 n; n = n->next) { 278 n->parent = backingstore_include_nodes[i].root; 279 n->parent->last = n; 280 } 281 backingstore_include_nodes[i].insertion_point->children = 282 backingstore_include_nodes[i].old_children; 283 for(n=backingstore_include_nodes[i].insertion_point->children; 284 n; n = n->next) { 285 n->parent->last = n; /* sets it to the last child */ 286 } 287 xmlFreeDoc(backingstore_include_nodes[i].doc); 288 } 289 } 290 free(backingstore_include_nodes); 291 } 292 backingstore_include_nodes = NULL; 293 backingstore_include_cnt = -1; 241 294 } 242 295 void … … 272 325 } 273 326 } 327 static u_int64_t 328 usec_now() { 329 u_int64_t usec; 330 struct timeval tv; 331 gettimeofday(&tv, NULL); 332 usec = tv.tv_sec * 1000000UL; 333 usec += tv.tv_usec; 334 return usec; 335 } 336 void 337 noit_conf_backingstore_remove(noit_conf_section_t vnode) { 338 xmlNodePtr node = vnode; 339 noit_xml_userdata_t *subctx = node->_private; 340 if(subctx) { 341 noitL(noit_debug, "marking %s for removal\n", subctx->path); 342 if(!backingstore_freelist) backingstore_freelist = subctx; 343 else { 344 noit_xml_userdata_t *fl = backingstore_freelist; 345 while(fl->freelist) fl = fl->freelist; 346 fl->freelist = subctx; 347 } 348 node->_private = NULL; 349 } 350 /* If we're deleted, we'll mark the parent as dirty */ 351 if(node->parent) noit_conf_backingstore_dirty(node->parent); 352 } 353 void 354 noit_conf_backingstore_dirty(noit_conf_section_t vnode) { 355 xmlNodePtr node = vnode; 356 noit_xml_userdata_t *subctx = node->_private; 357 if(subctx) { 358 subctx->dirty_time = usec_now(); 359 return; 360 } 361 if(node->parent) noit_conf_backingstore_dirty(node->parent); 362 } 363 int 364 noit_conf_backingstore_write(noit_xml_userdata_t *ctx, noit_boolean skip, 365 xmlAttrPtr attrs, xmlNodePtr node) { 366 int failure = 0; 367 char newpath[PATH_MAX]; 368 xmlNodePtr n; 369 snprintf(newpath, sizeof(newpath), "%s/.attrs", ctx->path); 370 if(attrs) { 371 xmlDocPtr tmpdoc; 372 xmlNodePtr tmpnode; 373 noitL(noit_debug, " **> %s\n", newpath); 374 tmpdoc = xmlNewDoc((xmlChar *)"1.0"); 375 tmpnode = xmlNewNode(NULL, ctx->name ? (xmlChar *)ctx->name : (xmlChar *)"stub"); 376 xmlDocSetRootElement(tmpdoc, tmpnode); 377 tmpnode->properties = attrs; 378 failure = noit_xmlSaveToFile(tmpdoc, newpath); 379 tmpnode->properties = NULL; 380 xmlFreeDoc(tmpdoc); 381 if(failure) return -1; 382 } 383 else if(!skip) { 384 unlink(newpath); 385 } 386 for(n = node; n; n = n->next) { 387 int leaf; 388 noit_xml_userdata_t *subctx; 389 subctx = n->_private; 390 leaf = is_stopnode(n); 391 if(!subctx) { /* This has never been written out */ 392 subctx = calloc(1, sizeof(*subctx)); 393 subctx->name = strdup((char *)n->name); 394 snprintf(newpath, sizeof(newpath), "%s/%s#%llu", ctx->path, n->name, ++max_gen_count); 395 if(leaf) strlcat(newpath, ".xml", sizeof(newpath)); 396 subctx->path = strdup(newpath); 397 subctx->dirty_time = usec_now(); 398 n->_private = subctx; 399 noitL(noit_debug, " !!> %s\n", subctx->path); 400 } 401 if(leaf) { 402 xmlDocPtr tmpdoc; 403 xmlNodePtr tmpnode; 404 if(subctx->dirty_time > last_config_flush) { 405 tmpdoc = xmlNewDoc((xmlChar *)"1.0"); 406 tmpnode = xmlNewNode(NULL, n->name); 407 xmlDocSetRootElement(tmpdoc, tmpnode); 408 tmpnode->properties = n->properties; 409 tmpnode->children = n->children; 410 failure = noit_xmlSaveToFile(tmpdoc, subctx->path); 411 tmpnode->properties = NULL; 412 tmpnode->children = NULL; 413 xmlFreeDoc(tmpdoc); 414 noitL(noit_debug, " ==> %s\n", subctx->path); 415 if(failure) return -1; 416 } 417 } 418 else { 419 noit_boolean skip_attrs; 420 skip_attrs = leaf || (subctx->dirty_time <= last_config_flush); 421 noitL(noit_debug, " --> %s\n", subctx->path); 422 if(noit_conf_backingstore_write(subctx, skip_attrs, skip_attrs ? NULL : n->properties, n->children)) 423 return -1; 424 } 425 } 426 return 0; 427 } 428 void 429 noit_conf_shatter_write(xmlDocPtr doc) { 430 if(backingstore_freelist) { 431 noit_xml_userdata_t *fl, *last; 432 for(fl = backingstore_freelist; fl; ) { 433 last = fl; 434 fl = fl->freelist; 435 /* If it is a file, we'll unlink it, otherwise, 436 * we need to delete the attributes and the directory. 437 */ 438 if(unlink(last->path)) { 439 char attrpath[PATH_MAX]; 440 snprintf(attrpath, sizeof(attrpath), "%s/.attrs", last->path); 441 unlink(attrpath); 442 if(rmdir(last->path) && errno != ENOENT) { 443 /* This shouldn't happen, but if it does we risk 444 * leaving a mess. Don't do that. 445 */ 446 noitL(noit_error, "backingstore mess %s: %s\n", 447 last->path, strerror(errno)); 448 } 449 } 450 noit_xml_userdata_free(last); 451 } 452 backingstore_freelist = NULL; 453 } 454 if(backingstore_include_nodes) { 455 int i; 456 for(i=0; i<backingstore_include_cnt; i++) { 457 if(backingstore_include_nodes[i].doc) { 458 xmlNodePtr n; 459 noit_xml_userdata_t *what = backingstore_include_nodes[i].doc->_private; 460 461 for(n=backingstore_include_nodes[i].insertion_point->children; 462 n; n = n->next) { 463 n->parent = backingstore_include_nodes[i].root; 464 n->parent->last = n; 465 } 466 backingstore_include_nodes[i].root->children = 467 backingstore_include_nodes[i].insertion_point->children; 468 backingstore_include_nodes[i].insertion_point->children = 469 backingstore_include_nodes[i].old_children; 470 for(n=backingstore_include_nodes[i].insertion_point->children; 471 n; n = n->next) { 472 n->parent->last = n; /* sets it to the last child */ 473 } 474 noit_conf_backingstore_write(what, noit_false, NULL, backingstore_include_nodes[i].root->children); 475 } 476 } 477 last_config_flush = usec_now(); 478 } 479 } 480 void 481 noit_conf_shatter_postwrite(xmlDocPtr doc) { 482 if(backingstore_include_nodes) { 483 int i; 484 for(i=0; i<backingstore_include_cnt; i++) { 485 if(backingstore_include_nodes[i].doc) { 486 xmlNodePtr n; 487 backingstore_include_nodes[i].insertion_point->children = 488 backingstore_include_nodes[i].root->children; 489 for(n=backingstore_include_nodes[i].insertion_point->children; 490 n; n = n->next) { 491 n->parent = backingstore_include_nodes[i].insertion_point; 492 n->parent->last = n; 493 } 494 } 495 } 496 } 497 } 498 499 int 500 noit_conf_read_into_node(xmlNodePtr node, const char *path) { 501 DIR *dirroot; 502 struct dirent *de, *entry; 503 char filepath[PATH_MAX]; 504 xmlDocPtr doc; 505 xmlNodePtr root = NULL; 506 xmlAttrPtr a; 507 struct stat sb; 508 int size, rv; 509 510 noitL(noit_debug, "read backing store: %s\n", path); 511 snprintf(filepath, sizeof(filepath), "%s/.attrs", path); 512 while((rv = stat(filepath, &sb)) < 0 && errno == EINTR); 513 if(rv == 0) { 514 doc = xmlParseFile(filepath); 515 if(doc) root = xmlDocGetRootElement(doc); 516 if(doc && root) { 517 node->properties = root->properties; 518 for(a = node->properties; a; a = a->next) { 519 a->parent = node; 520 a->doc = node->doc; 521 } 522 root->properties = NULL; 523 xmlFreeDoc(doc); 524 doc = NULL; 525 } 526 } 527 #ifdef _PC_NAME_MAX 528 size = pathconf(path, _PC_NAME_MAX); 529 #endif 530 size = MAX(size, PATH_MAX + 128); 531 de = alloca(size); 532 dirroot = opendir(path); 533 if(!dirroot) return -1; 534 while(portable_readdir_r(dirroot, de, &entry) == 0 && entry != NULL) { 535 noit_xml_userdata_t *udata; 536 char name[PATH_MAX]; 537 char *sep; 538 xmlNodePtr child; 539 u_int64_t gen; 540 541 sep = strchr(entry->d_name, '#'); 542 if(!sep) continue; 543 snprintf(filepath, sizeof(filepath), "%s/%s", path, entry->d_name); 544 while((rv = stat(filepath, &sb)) < 0 && errno == EINTR); 545 if(rv == 0) { 546 strlcpy(name, entry->d_name, sizeof(name)); 547 name[sep - entry->d_name] = '\0'; 548 gen = strtoull(sep+1, NULL, 10); 549 if(gen > max_gen_count) max_gen_count = gen; 550 551 if(S_ISDIR(sb.st_mode)) { 552 noitL(noit_debug, "<DIR< %s\n", entry->d_name); 553 child = xmlNewNode(NULL, (xmlChar *)name); 554 noit_conf_read_into_node(child, filepath); 555 udata = calloc(1, sizeof(*udata)); 556 udata->name = strdup(name); 557 udata->path = strdup(filepath); 558 child->_private = udata; 559 xmlAddChild(node, child); 560 } 561 else if(S_ISREG(sb.st_mode)) { 562 xmlDocPtr cdoc; 563 xmlNodePtr cnode = NULL; 564 noitL(noit_debug, "<FILE< %s\n", entry->d_name); 565 cdoc = xmlParseFile(filepath); 566 if(cdoc) { 567 cnode = xmlDocGetRootElement(cdoc); 568 xmlDocSetRootElement(cdoc, xmlNewNode(NULL, (xmlChar *)"dummy")); 569 if(cnode) { 570 udata = calloc(1, sizeof(*udata)); 571 udata->name = strdup(name); 572 udata->path = strdup(filepath); 573 cnode->_private = udata; 574 xmlAddChild(node, cnode); 575 } 576 xmlFreeDoc(cdoc); 577 } 578 } 579 } 580 } 581 closedir(dirroot); 582 return 0; 583 } 584 585 xmlDocPtr 586 noit_conf_read_backing_store(const char *path) { 587 xmlDocPtr doc; 588 xmlNodePtr root; 589 noit_xml_userdata_t *what; 590 591 doc = xmlNewDoc((xmlChar *)"1.0"); 592 what = calloc(1, sizeof(*what)); 593 what->path = strdup(path); 594 doc->_private = what; 595 root = xmlNewNode(NULL, (xmlChar *)"stub"); 596 xmlDocSetRootElement(doc, root); 597 noit_conf_read_into_node(root, path); 598 return doc; 599 } 274 600 int 275 601 noit_conf_magic_mix(const char *parentfile, xmlDocPtr doc) { … … 280 606 281 607 assert(config_include_cnt == -1); 282 608 assert(backingstore_include_cnt == -1); 609 610 backingstore_include_cnt = 0; 611 mix_ctxt = xmlXPathNewContext(doc); 612 pobj = xmlXPathEval((xmlChar *)"//*[@backingstore]", mix_ctxt); 613 if(!pobj) goto includes; 614 if(pobj->type != XPATH_NODESET) goto includes; 615 if(xmlXPathNodeSetIsEmpty(pobj->nodesetval)) goto includes; 616 cnt = xmlXPathNodeSetGetLength(pobj->nodesetval); 617 if(cnt > 0) 618 backingstore_include_nodes = calloc(cnt, sizeof(*backingstore_include_nodes)); 619 for(i=0; i<cnt; i++) { 620 char *path, *infile; 621 node = xmlXPathNodeSetItem(pobj->nodesetval, i); 622 path = (char *)xmlGetProp(node, (xmlChar *)"backingstore"); 623 if(!path) continue; 624 if(*path == '/') infile = strdup(path); 625 else { 626 char *cp; 627 infile = malloc(PATH_MAX); 628 strlcpy(infile, parentfile, PATH_MAX); 629 for(cp = infile + strlen(infile) - 1; cp > infile; cp--) { 630 if(*cp == '/') { *cp = '\0'; break; } 631 else *cp = '\0'; 632 } 633 strlcat(infile, "/", PATH_MAX); 634 strlcat(infile, path, PATH_MAX); 635 } 636 xmlFree(path); 637 backingstore_include_nodes[i].doc = noit_conf_read_backing_store(infile); 638 if(backingstore_include_nodes[i].doc) { 639 xmlNodePtr n, lchild; 640 backingstore_include_nodes[i].insertion_point = node; 641 backingstore_include_nodes[i].root = xmlDocGetRootElement(backingstore_include_nodes[i].doc); 642 /* for backing store, they are permanently reattached under the backing store. 643 * so for any children, we need to glue them into the new parent document. 644 */ 645 lchild = backingstore_include_nodes[i].root->children; 646 while(lchild && lchild->next) lchild = lchild->next; 647 if(lchild) { 648 lchild->next = node->children; 649 if(node->children) node->children->prev = lchild; 650 } 651 else 652 backingstore_include_nodes[i].root->children = node->children; 653 for(n=node->children; n; n = n->next) { 654 n->parent = backingstore_include_nodes[i].root; /* this gets mapped right back, just for clarity */ 655 n->doc = backingstore_include_nodes[i].doc; 656 } 657 backingstore_include_nodes[i].old_children = NULL; 658 node->children = backingstore_include_nodes[i].root->children; 659 for(n=node->children; n; n = n->next) { 660 n->parent = backingstore_include_nodes[i].insertion_point; 661 n->parent->last = n; 662 } 663 } 664 else { 665 noitL(noit_error, "Could not load: '%s'\n", infile); 666 rv = -1; 667 } 668 free(infile); 669 } 670 mix_ctxt = xmlXPathNewContext(doc); 671 backingstore_include_cnt = cnt; 672 noitL(noit_debug, "Processed %d backing stores.\n", backingstore_include_cnt); 673 if(pobj) xmlXPathFreeObject(pobj); 674 675 includes: 283 676 config_include_cnt = 0; 284 mix_ctxt = xmlXPathNewContext(doc);285 677 pobj = xmlXPathEval((xmlChar *)"//include[@file]", mix_ctxt); 286 678 if(!pobj) goto out; … … 850 1242 } 851 1243 noit_conf_kansas_city_shuffle_undo(master_config); 1244 noit_conf_shatter_write(master_config); 852 1245 len = xmlSaveFormatFileTo(out, master_config, "utf8", 1); 1246 noit_conf_shatter_postwrite(master_config); 853 1247 noit_conf_kansas_city_shuffle_redo(master_config); 854 1248 close(fd); … … 903 1297 xmlCharEncodingHandlerPtr enc; 904 1298 struct config_line_vstr *clv; 1299 noit_boolean notify_only = noit_false; 1300 const char *v; 905 1301 SETUP_LOG(config, return -1); 1302 v = noit_log_stream_get_property(config_log, "notify_only"); 1303 if(v && !strcmp(v, "on")) notify_only = noit_true; 906 1304 907 1305 /* We know we haven't changed */ 908 1306 if(last_write_gen == __config_gen) return 0; 909 910 1307 gettimeofday(&__now, NULL); 1308 1309 if(notify_only) { 1310 noitL(config_log, "n\t%lu.%03lu\t%d\t\n", 1311 (unsigned long int)__now.tv_sec, 1312 (unsigned long int)__now.tv_usec / 1000UL, 0); 1313 last_write_gen = __config_gen; 1314 return 0; 1315 } 1316 911 1317 clv = calloc(1, sizeof(*clv)); 912 1318 clv->target = CONFIG_B64; … … 1215 1621 if(delete) { 1216 1622 node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, 0); 1623 CONF_REMOVE(node); 1217 1624 xmlUnlinkNode(node); 1218 1625 noit_conf_mark_changed(); src/noit_conf.h
rc6c11c3 r80f4747 133 133 API_EXPORT(int) noit_conf_log_init_rotate(const char *, noit_boolean); 134 134 135 API_EXPORT(void) noit_conf_backingstore_remove(noit_conf_section_t node); 136 API_EXPORT(void) noit_conf_backingstore_dirty(noit_conf_section_t node); 137 138 #define CONF_REMOVE(n) do { \ 139 noit_conf_backingstore_remove(n); \ 140 } while(0) 141 142 #define CONF_DIRTY(n) do { \ 143 noit_conf_backingstore_dirty(n); \ 144 noit_conf_mark_changed(); \ 145 } while(0) 146 135 147 #define EXPOSE_CHECKER(name) \ 136 148 API_EXPORT(pcre *) noit_conf_get_valid_##name##_checker() src/noit_conf_checks.c
r022178b r8e9cf57 173 173 if(val) 174 174 xmlSetProp(node, (xmlChar *)attrinfo->name, (xmlChar *)val); 175 CONF_DIRTY(node); 175 176 noit_conf_mark_changed(); 176 177 } … … 212 213 } 213 214 else { 215 CONF_DIRTY(newnode); 214 216 noit_conf_mark_changed(); 215 217 rv = 0; … … 586 588 for(j=1;j<argc;j++) 587 589 xmlUnsetProp(node, (xmlChar *)argv[j]); 590 CONF_DIRTY(node); 588 591 } else { 589 592 nc_printf(ncct, "descheduling %s\n", uuid_conf); 590 593 noit_poller_deschedule(checkid); 594 CONF_REMOVE(node); 591 595 xmlUnlinkNode(node); 592 596 } … … 904 908 xmlNodePtr toremove; 905 909 toremove = xmlXPathNodeSetItem(pobj->nodesetval, 0); 910 CONF_REMOVE(toremove); 906 911 xmlUnlinkNode(toremove); 907 912 } … … 934 939 /* Now we create a child */ 935 940 xmlNewChild(confignode, NULL, (xmlChar *)name, (xmlChar *)value); 941 CONF_DIRTY(confignode); 936 942 } 937 943 noit_conf_mark_changed(); … … 1006 1012 if(value) 1007 1013 xmlSetProp(node, (xmlChar *)attrinfo->name, (xmlChar *)value); 1014 CONF_DIRTY(node); 1008 1015 noit_conf_mark_changed(); 1009 1016 rv = 0; src/noit_filters_rest.c
r637731d r8e9cf57 148 148 if(!node) goto not_found; 149 149 if(noit_filter_remove(node) == 0) goto not_found; 150 CONF_REMOVE(node); 150 151 xmlUnlinkNode(node); 151 152 xmlFreeNode(node); src/noit_xml.c
rc30a0fe r8e9cf57 31 31 */ 32 32 33 #include "noit_defines.h" 33 34 #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> 34 40 #include <assert.h> 35 41 … … 85 91 } 86 92 93 int 94 noit_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 40 40 noit_xmlSaveToBuffer(xmlDocPtr doc); 41 41 42 API_EXPORT(int) 43 noit_xmlSaveToFile(xmlDocPtr doc, const char *filename); 44 42 45 #endif src/stratcon_jlog_streamer.c
r39120ca r8e9cf57 1463 1463 pthread_mutex_unlock(&noit_ip_by_cn_lock); 1464 1464 } 1465 CONF_REMOVE(noit_configs[i]); 1465 1466 xmlUnlinkNode(noit_configs[i]); 1466 1467 xmlFreeNode(noit_configs[i]);