Merge remote-tracking branch 'origin/master' into dav

Conflicts:
	config/ocsync_log.conf
	src/csync.c
	src/csync.h
	src/csync_config.c
	src/csync_log.h
	src/csync_private.h
	src/csync_statedb.c
	tests/csync_tests/check_csync_config.c
This commit is contained in:
Olivier Goffart 2012-12-03 17:32:08 +01:00
commit 95edd6a9de
28 changed files with 925 additions and 567 deletions

View file

@ -39,7 +39,6 @@ macro_ensure_out_of_source_build("${PROJECT_NAME} requires an out of source buil
include(MacroAddPlugin)
include(MacroCopyFile)
find_package(Log4C)
find_package(CMocka)
if (CMOCKA_FOUND AND UNIT_TESTING)
include(AddCMockaTest)

View file

@ -1,4 +1,3 @@
option(WITH_LOG4C "Build csync without log4c" ON)
option(UNIT_TESTING "Build with unit tests" OFF)
option(MEM_NULL_TESTS "Enable NULL memory testing" OFF)
option(LOG_TO_CALLBACK "Enable extended logging through a callback" OFF)

View file

@ -9,14 +9,13 @@ In order to build csync, you need to install several components:
- A C compiler
- [CMake](http://www.cmake.org) >= 2.6.0.
- [check](http://check.sourceforge.net) >= 0.9.5
- [log4c](http://log4c.sourceforge.net) >= 1.2
- [sqlite3](http://www.sqlite.org) >= 3.4
- [libiniparser](http://ndevilla.free.fr/iniparser/) >= 2.10
- [libsmbclient](http://www.samba.org) >= 3.5
- [libssh](http://www.libssh.org) >= 0.5
log4c and sqlite3 are runtime requirements too. libsmbclient is needed for
sqlite3 is a runtime requirement. libsmbclient is needed for
the smb plugin, libssh for the sftp plugin.
Note that these version numbers are version we know works correctly. If you

View file

@ -49,7 +49,8 @@ at LOCAL with the ones at REMOTE.\n\
\n\
-c, --conflict-copys Create conflict copys if file changed on both\n\
sides.\n\
-d, --disable-statedb Disable the usage and creation of a statedb.\n\
-d, --debug-level=DEBUGLVL Set debug level\n\
--disable-statedb Disable the usage and creation of a statedb.\n\
--dry-run This runs only update detection and reconcilation.\n\
\n\
--exclude-file=<file> Add an additional exclude file\n\
@ -65,7 +66,8 @@ at LOCAL with the ones at REMOTE.\n\
static const struct option long_options[] =
{
{"exclude-file", required_argument, 0, 0 },
{"disable-statedb", no_argument, 0, 'd' },
{"debug-level", required_argument, 0, 'd' },
{"disable-statedb", no_argument, 0, 0 },
{"dry-run", no_argument, 0, 0 },
{"test-statedb", no_argument, 0, 0 },
{"conflict-copies", no_argument, 0, 'c' },
@ -79,6 +81,7 @@ static const struct option long_options[] =
struct argument_s {
char *args[2]; /* SOURCE and DESTINATION */
char *exclude_file;
int debug_level;
int disable_statedb;
int create_statedb;
int update;
@ -112,8 +115,9 @@ static int parse_args(struct argument_s *csync_args, int argc, char **argv)
switch(result) {
case 'd':
csync_args->disable_statedb = 1;
/* printf("Argument: Disable Statedb\n"); */
if (optarg != NULL) {
csync_args->debug_level = atoi(optarg);
}
break;
case 'c':
csync_args->with_conflict_copys = true;
@ -130,6 +134,8 @@ static int parse_args(struct argument_s *csync_args, int argc, char **argv)
if(c_streq(opt->name, "exclude-file")) {
csync_args->exclude_file = c_strdup(optarg);
/* printf("Argument: exclude-file: %s\n", csync_args->exclude_file); */
} else if(c_streq(opt->name, "disable-statedb")) {
csync_args->disable_statedb = 1;
} else if(c_streq(opt->name, "test-update")) {
csync_args->create_statedb = 0;
csync_args->update = 1;
@ -174,6 +180,7 @@ int main(int argc, char **argv) {
/* Default values. */
arguments.exclude_file = NULL;
arguments.debug_level = 4;
arguments.disable_statedb = 0;
arguments.create_statedb = 0;
arguments.update = 1;
@ -211,10 +218,15 @@ int main(int argc, char **argv) {
}
csync_set_auth_callback(csync, csync_getpass);
if (arguments.debug_level) {
csync_set_log_verbosity(csync, arguments.debug_level);
}
if (arguments.disable_statedb) {
csync_disable_statedb(csync);
}
if(arguments.with_conflict_copys)
{
csync_enable_conflictcopys(csync);

View file

@ -1,36 +0,0 @@
# - Try to find Log4C
# Once done this will define
#
# LOG4C_FOUND - system has Log4C
# LOG4C_INCLUDE_DIRS - the Log4C include directory
# LOG4C_LIBRARIES - Link these to use Log4C
# LOG4C_DEFINITIONS - Compiler switches required for using Log4C
#
# Copyright (c) 2009 Andreas Schneider <mail@cynapses.org>
#
# Redistribution and use is allowed according to the terms of the New
# BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
#
include(GNUInstallDirs)
find_path(LOG4C_INCLUDE_DIRS
NAMES
log4c.h
HINTS
${CMAKE_INSTALL_INCLUDEDIR}
)
find_library(LOG4C_LIBRARIES
NAMES
log4c
HINTS
${CMAKE_INSTALL_LIBDIR}
)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Log4C DEFAULT_MSG LOG4C_LIBRARIES LOG4C_INCLUDE_DIRS)
# show the LOG4C_INCLUDE_DIRS and LOG4C_LIBRARIES variables only in the advanced view
mark_as_advanced(LOG4C_INCLUDE_DIRS LOG4C_LIBRARIES)

View file

@ -1,49 +0,0 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE log4c SYSTEM "">
<log4c version="1.2.1">
<!-- root category ========================================= -->
<category name="root" priority="none"/>
<!-- Categories for more verbose logging output ============ -->
<!--
** As a user you may be interested in the "debug" priority and
** use "file" as the appender.
-->
<category name="csync.updater" priority="notice" appender="stderr"/>
<category name="csync.reconciler" priority="notice" appender="stderr"/>
<category name="csync.propagator" priority="notice" appender="stderr"/>
<!-- Categories debug logging output ============ -->
<category name="csync.api" priority="notice" appender="stderr"/>
<category name="csync.config" priority="notice" appender="stderr"/>
<category name="csync.statedb" priority="notice" appender="stderr"/>
<category name="csync.lock" priority="notice" appender="stderr"/>
<category name="csync.time" priority="notice" appender="stderr"/>
<category name="csync.util" priority="notice" appender="stderr"/>
<category name="csync.vio.main" priority="notice" appender="stderr"/>
<!-- Default appenders ===================================== -->
<appender name="stdout" type="stream" layout="basic"/>
<appender name="stderr" type="stream" layout="dated"/>
<appender name="syslog" type="syslog" layout="basic"/>
<appender name="file" type="rollingfile" logdir="." prefix="csync.log"
layout="dated" rollingpolicy="csync_rollingpolicy"/>
<!-- Default layouts ======================================= -->
<layout name="basic" type="basic"/>
<layout name="dated" type="dated"/>
<!-- Default policies ===================================== -->
<rollingpolicy name="csync_rollingpolicy" type="sizewin" maxsize="1024000"
maxnum="100000" />
<!-- log4c config variables, don't touch them. -->
<config>
<bufsize>0</bufsize>
<debug level="0"/>
<nocleanup>0</nocleanup>
</config>
</log4c>

View file

@ -287,23 +287,8 @@ The entries in the file are newline separated. Use
Debug messages and dry run
~~~~~~~~~~~~~~~~~~~~~~~~~~
For log messages csync uses log4c. It is a logging mechanism which uses debug
levels and categories. There is a config file where you can specify the debug
level for each component. It is located at '~/.csync/csync_log.conf'.
Available debug priorities are:
* trace
* debug
* info
* warn
* error
* fatal
* none
A more detailed description can be found at the
link:http://log4c.sourceforge.net/[log4c homepage]. A good introduction can
be found link:http://logging.apache.org/log4j/1.2/manual.html[here].
By default the csync client logs to stderr and you can increase the debug
level with a commandline options.
To simulate a run of the file synchronizer, you should set the priority to
'debug' for the categories 'csync.updater' and 'csync.reconciler' in the config

View file

@ -2,15 +2,25 @@
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="generator" content="AsciiDoc 8.4.5" />
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
<meta name="generator" content="AsciiDoc 8.6.6" />
<title>CSYNC User Guide</title>
<style type="text/css">
/* Debug borders */
p, li, dt, dd, div, pre, h1, h2, h3, h4, h5, h6 {
/*
border: 1px solid red;
*/
/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
/* Default font. */
body {
font-family: Georgia,serif;
}
/* Title font. */
h1, h2, h3, h4, h5, h6,
div.title, caption.title,
thead, p.table.header,
#toctitle,
#author, #revnumber, #revdate, #revremark,
#footer {
font-family: Arial,Helvetica,sans-serif;
}
body {
@ -35,13 +45,8 @@ strong {
color: #083194;
}
tt {
color: navy;
}
h1, h2, h3, h4, h5, h6 {
color: #527bbd;
font-family: sans-serif;
margin-top: 1.2em;
margin-bottom: 0.5em;
line-height: 1.3;
@ -59,9 +64,11 @@ h3 {
h3 + * {
clear: left;
}
h5 {
font-size: 1.0em;
}
div.sectionbody {
font-family: serif;
margin-left: 0;
}
@ -77,53 +84,54 @@ p {
ul, ol, li > p {
margin-top: 0;
}
ul > li { color: #aaa; }
ul > li > * { color: black; }
pre {
padding: 0;
margin: 0;
}
span#author {
#author {
color: #527bbd;
font-family: sans-serif;
font-weight: bold;
font-size: 1.1em;
}
span#email {
#email {
}
span#revnumber, span#revdate, span#revremark {
font-family: sans-serif;
#revnumber, #revdate, #revremark {
}
div#footer {
font-family: sans-serif;
#footer {
font-size: small;
border-top: 2px solid silver;
padding-top: 0.5em;
margin-top: 4.0em;
}
div#footer-text {
#footer-text {
float: left;
padding-bottom: 0.5em;
}
div#footer-badges {
#footer-badges {
float: right;
padding-bottom: 0.5em;
}
div#preamble {
#preamble {
margin-top: 1.5em;
margin-bottom: 1.5em;
}
div.tableblock, div.imageblock, div.exampleblock, div.verseblock,
div.imageblock, div.exampleblock, div.verseblock,
div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
div.admonitionblock {
margin-top: 1.5em;
margin-top: 1.0em;
margin-bottom: 1.5em;
}
div.admonitionblock {
margin-top: 2.5em;
margin-bottom: 2.5em;
margin-top: 2.0em;
margin-bottom: 2.0em;
margin-right: 10%;
color: #606060;
}
div.content { /* Block element content. */
@ -133,7 +141,6 @@ div.content { /* Block element content. */
/* Block element titles. */
div.title, caption.title {
color: #527bbd;
font-family: sans-serif;
font-weight: bold;
text-align: left;
margin-top: 1.0em;
@ -155,31 +162,34 @@ div.content + div.title {
div.sidebarblock > div.content {
background: #ffffee;
border: 1px solid silver;
border: 1px solid #dddddd;
border-left: 4px solid #f0f0f0;
padding: 0.5em;
}
div.listingblock > div.content {
border: 1px solid silver;
background: #f4f4f4;
border: 1px solid #dddddd;
border-left: 5px solid #f0f0f0;
background: #f8f8f8;
padding: 0.5em;
}
div.quoteblock {
padding-left: 2.0em;
div.quoteblock, div.verseblock {
padding-left: 1.0em;
margin-left: 1.0em;
margin-right: 10%;
border-left: 5px solid #f0f0f0;
color: #888;
}
div.quoteblock > div.attribution {
padding-top: 0.5em;
text-align: right;
}
div.verseblock {
padding-left: 2.0em;
margin-right: 10%;
}
div.verseblock > div.content {
white-space: pre;
div.verseblock > pre.content {
font-family: inherit;
font-size: inherit;
}
div.verseblock > div.attribution {
padding-top: 0.75em;
@ -200,12 +210,12 @@ div.admonitionblock .icon {
}
div.admonitionblock td.content {
padding-left: 0.5em;
border-left: 2px solid silver;
border-left: 3px solid #dddddd;
}
div.exampleblock > div.content {
border-left: 2px solid silver;
padding: 0.5em;
border-left: 3px solid #dddddd;
padding-left: 0.5em;
}
div.imageblock div.content { padding-left: 0; }
@ -252,35 +262,12 @@ div.compact div, div.compact div {
margin-bottom: 0.1em;
}
div.tableblock > table {
border: 3px solid #527bbd;
}
thead {
font-family: sans-serif;
font-weight: bold;
}
tfoot {
font-weight: bold;
}
td > div.verse {
white-space: pre;
}
p.table {
margin-top: 0;
}
/* Because the table frame attribute is overriden by CSS in most browsers. */
div.tableblock > table[frame="void"] {
border-style: none;
}
div.tableblock > table[frame="hsides"] {
border-left-style: none;
border-right-style: none;
}
div.tableblock > table[frame="vsides"] {
border-top-style: none;
border-bottom-style: none;
}
div.hdlist {
margin-top: 0.8em;
@ -310,13 +297,52 @@ div.hdlist.compact tr {
background: yellow;
}
@media print {
div#footer-badges { display: none; }
.footnote, .footnoteref {
font-size: 0.8em;
}
div#toctitle {
span.footnote, span.footnoteref {
vertical-align: super;
}
#footnotes {
margin: 20px 0 20px 0;
padding: 7px 0 0 0;
}
#footnotes div.footnote {
margin: 0 0 5px 0;
}
#footnotes hr {
border: none;
border-top: 1px solid silver;
height: 1px;
text-align: left;
margin-left: 0;
width: 20%;
min-width: 100px;
}
div.colist td {
padding-right: 0.5em;
padding-bottom: 0.3em;
vertical-align: top;
}
div.colist td img {
margin-top: 0.3em;
}
@media print {
#footer-badges { display: none; }
}
#toc {
margin-bottom: 2.5em;
}
#toctitle {
color: #527bbd;
font-family: sans-serif;
font-size: 1.1em;
font-weight: bold;
margin-top: 1.0em;
@ -339,51 +365,187 @@ div.toclevel4 {
margin-left: 6em;
font-size: 0.9em;
}
/* Workarounds for IE6's broken and incomplete CSS2. */
div.sidebar-content {
background: #ffffee;
border: 1px solid silver;
padding: 0.5em;
span.aqua { color: aqua; }
span.black { color: black; }
span.blue { color: blue; }
span.fuchsia { color: fuchsia; }
span.gray { color: gray; }
span.green { color: green; }
span.lime { color: lime; }
span.maroon { color: maroon; }
span.navy { color: navy; }
span.olive { color: olive; }
span.purple { color: purple; }
span.red { color: red; }
span.silver { color: silver; }
span.teal { color: teal; }
span.white { color: white; }
span.yellow { color: yellow; }
span.aqua-background { background: aqua; }
span.black-background { background: black; }
span.blue-background { background: blue; }
span.fuchsia-background { background: fuchsia; }
span.gray-background { background: gray; }
span.green-background { background: green; }
span.lime-background { background: lime; }
span.maroon-background { background: maroon; }
span.navy-background { background: navy; }
span.olive-background { background: olive; }
span.purple-background { background: purple; }
span.red-background { background: red; }
span.silver-background { background: silver; }
span.teal-background { background: teal; }
span.white-background { background: white; }
span.yellow-background { background: yellow; }
span.big { font-size: 2em; }
span.small { font-size: 0.6em; }
span.underline { text-decoration: underline; }
span.overline { text-decoration: overline; }
span.line-through { text-decoration: line-through; }
/*
* xhtml11 specific
*
* */
tt {
font-family: monospace;
font-size: inherit;
color: navy;
}
div.sidebar-title, div.image-title {
color: #527bbd;
font-family: sans-serif;
div.tableblock {
margin-top: 1.0em;
margin-bottom: 1.5em;
}
div.tableblock > table {
border: 3px solid #527bbd;
}
thead, p.table.header {
font-weight: bold;
margin-top: 0.0em;
margin-bottom: 0.5em;
color: #527bbd;
}
p.table {
margin-top: 0;
}
/* Because the table frame attribute is overriden by CSS in most browsers. */
div.tableblock > table[frame="void"] {
border-style: none;
}
div.tableblock > table[frame="hsides"] {
border-left-style: none;
border-right-style: none;
}
div.tableblock > table[frame="vsides"] {
border-top-style: none;
border-bottom-style: none;
}
div.listingblock div.content {
border: 1px solid silver;
background: #f4f4f4;
padding: 0.5em;
/*
* html5 specific
*
* */
.monospaced {
font-family: monospace;
font-size: inherit;
color: navy;
}
div.quoteblock-attribution {
padding-top: 0.5em;
table.tableblock {
margin-top: 1.0em;
margin-bottom: 1.5em;
}
thead, p.tableblock.header {
font-weight: bold;
color: #527bbd;
}
p.tableblock {
margin-top: 0;
}
table.tableblock {
border-width: 3px;
border-spacing: 0px;
border-style: solid;
border-color: #527bbd;
border-collapse: collapse;
}
th.tableblock, td.tableblock {
border-width: 1px;
padding: 4px;
border-style: solid;
border-color: #527bbd;
}
table.tableblock.frame-topbot {
border-left-style: hidden;
border-right-style: hidden;
}
table.tableblock.frame-sides {
border-top-style: hidden;
border-bottom-style: hidden;
}
table.tableblock.frame-none {
border-style: hidden;
}
th.tableblock.halign-left, td.tableblock.halign-left {
text-align: left;
}
th.tableblock.halign-center, td.tableblock.halign-center {
text-align: center;
}
th.tableblock.halign-right, td.tableblock.halign-right {
text-align: right;
}
div.verseblock-content {
white-space: pre;
th.tableblock.valign-top, td.tableblock.valign-top {
vertical-align: top;
}
div.verseblock-attribution {
padding-top: 0.75em;
text-align: left;
th.tableblock.valign-middle, td.tableblock.valign-middle {
vertical-align: middle;
}
th.tableblock.valign-bottom, td.tableblock.valign-bottom {
vertical-align: bottom;
}
div.exampleblock-content {
border-left: 2px solid silver;
padding-left: 0.5em;
/*
* manpage specific
*
* */
body.manpage h1 {
padding-top: 0.5em;
padding-bottom: 0.5em;
border-top: 2px solid silver;
border-bottom: 2px solid silver;
}
body.manpage h2 {
border-style: none;
}
body.manpage div.sectionbody {
margin-left: 3em;
}
/* IE6 sets dynamically generated links as visited. */
div#toc a:visited { color: blue; }
@media print {
body.manpage div#toc { display: none; }
}
</style>
<script type="text/javascript">
/*<![CDATA[*/
window.onload = function(){generateToc(2)}
var asciidoc = { // Namespace.
/////////////////////////////////////////////////////////////////////
// Table Of Contents generator
/////////////////////////////////////////////////////////////////////
/* Author: Mihai Bazon, September 2002
* http://students.infoiasi.ro/~mishoo
*
@ -395,53 +557,74 @@ window.onload = function(){generateToc(2)}
*/
/* modified by Troy D. Hanson, September 2006. License: GPL */
/* modified by Stuart Rackham, October 2006. License: GPL */
/* modified by Stuart Rackham, 2006, 2009. License: GPL */
function getText(el) {
var text = "";
for (var i = el.firstChild; i != null; i = i.nextSibling) {
if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
text += i.data;
else if (i.firstChild != null)
text += getText(i);
}
return text;
}
// toclevels = 1..4.
toc: function (toclevels) {
function TocEntry(el, text, toclevel) {
this.element = el;
this.text = text;
this.toclevel = toclevel;
}
function tocEntries(el, toclevels) {
var result = new Array;
var re = new RegExp('[hH]([2-'+(toclevels+1)+'])');
// Function that scans the DOM tree for header elements (the DOM2
// nodeIterator API would be a better technique but not supported by all
// browsers).
var iterate = function (el) {
function getText(el) {
var text = "";
for (var i = el.firstChild; i != null; i = i.nextSibling) {
if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
var mo = re.exec(i.tagName)
if (mo)
result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
iterate(i);
if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
text += i.data;
else if (i.firstChild != null)
text += getText(i);
}
return text;
}
function TocEntry(el, text, toclevel) {
this.element = el;
this.text = text;
this.toclevel = toclevel;
}
function tocEntries(el, toclevels) {
var result = new Array;
var re = new RegExp('[hH]([2-'+(toclevels+1)+'])');
// Function that scans the DOM tree for header elements (the DOM2
// nodeIterator API would be a better technique but not supported by all
// browsers).
var iterate = function (el) {
for (var i = el.firstChild; i != null; i = i.nextSibling) {
if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
var mo = re.exec(i.tagName);
if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
}
iterate(i);
}
}
}
iterate(el);
return result;
}
iterate(el);
return result;
}
// This function does the work. toclevels = 1..4.
function generateToc(toclevels) {
var toc = document.getElementById("toc");
var entries = tocEntries(document.getElementsByTagName("body")[0], toclevels);
if (!toc) {
return;
}
// Delete existing TOC entries in case we're reloading the TOC.
var tocEntriesToRemove = [];
var i;
for (i = 0; i < toc.childNodes.length; i++) {
var entry = toc.childNodes[i];
if (entry.nodeName == 'div'
&& entry.getAttribute("class")
&& entry.getAttribute("class").match(/^toclevel/))
tocEntriesToRemove.push(entry);
}
for (i = 0; i < tocEntriesToRemove.length; i++) {
toc.removeChild(tocEntriesToRemove[i]);
}
// Rebuild TOC entries.
var entries = tocEntries(document.getElementById("content"), toclevels);
for (var i = 0; i < entries.length; ++i) {
var entry = entries[i];
if (entry.element.id == "")
entry.element.id = "toc" + i;
entry.element.id = "_toc_" + i;
var a = document.createElement("a");
a.href = "#" + entry.element.id;
a.appendChild(document.createTextNode(entry.text));
@ -451,21 +634,116 @@ function generateToc(toclevels) {
toc.appendChild(div);
}
if (entries.length == 0)
document.getElementById("header").removeChild(toc);
toc.parentNode.removeChild(toc);
},
/////////////////////////////////////////////////////////////////////
// Footnotes generator
/////////////////////////////////////////////////////////////////////
/* Based on footnote generation code from:
* http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
*/
footnotes: function () {
// Delete existing footnote entries in case we're reloading the footnodes.
var i;
var noteholder = document.getElementById("footnotes");
if (!noteholder) {
return;
}
var entriesToRemove = [];
for (i = 0; i < noteholder.childNodes.length; i++) {
var entry = noteholder.childNodes[i];
if (entry.nodeName == 'div' && entry.getAttribute("class") == "footnote")
entriesToRemove.push(entry);
}
for (i = 0; i < entriesToRemove.length; i++) {
noteholder.removeChild(entriesToRemove[i]);
}
// Rebuild footnote entries.
var cont = document.getElementById("content");
var spans = cont.getElementsByTagName("span");
var refs = {};
var n = 0;
for (i=0; i<spans.length; i++) {
if (spans[i].className == "footnote") {
n++;
var note = spans[i].getAttribute("data-note");
if (!note) {
// Use [\s\S] in place of . so multi-line matches work.
// Because JavaScript has no s (dotall) regex flag.
note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
spans[i].innerHTML =
"[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
"' title='View footnote' class='footnote'>" + n + "</a>]";
spans[i].setAttribute("data-note", note);
}
noteholder.innerHTML +=
"<div class='footnote' id='_footnote_" + n + "'>" +
"<a href='#_footnoteref_" + n + "' title='Return to text'>" +
n + "</a>. " + note + "</div>";
var id =spans[i].getAttribute("id");
if (id != null) refs["#"+id] = n;
}
}
if (n == 0)
noteholder.parentNode.removeChild(noteholder);
else {
// Process footnoterefs.
for (i=0; i<spans.length; i++) {
if (spans[i].className == "footnoteref") {
var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
href = href.match(/#.*/)[0]; // Because IE return full URL.
n = refs[href];
spans[i].innerHTML =
"[<a href='#_footnote_" + n +
"' title='View footnote' class='footnote'>" + n + "</a>]";
}
}
}
},
install: function(toclevels) {
var timerId;
function reinstall() {
asciidoc.footnotes();
if (toclevels) {
asciidoc.toc(toclevels);
}
}
function reinstallAndRemoveTimer() {
clearInterval(timerId);
reinstall();
}
timerId = setInterval(reinstall, 500);
if (document.addEventListener)
document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
else
window.onload = reinstallAndRemoveTimer;
}
}
asciidoc.install(2);
/*]]>*/
</script>
</head>
<body>
<body class="article">
<div id="header">
<h1>CSYNC User Guide</h1>
<span id="author">Andreas Schneider</span><br />
<span id="email"><tt>&lt;<a href="mailto:mail@cynapses.org">mail@cynapses.org</a>&gt;</tt></span><br />
<div id="toc">
<div id="toctitle">Table of Contents</div>
<noscript><p><b>JavaScript must be enabled in your browser to display the table of contents.</b></p></noscript>
<div id="toc">
<div id="toctitle">Table of Contents</div>
<noscript><p><b>JavaScript must be enabled in your browser to display the table of contents.</b></p></noscript>
</div>
</div>
<div id="content">
<div id="preamble">
<div class="sectionbody">
<div class="paragraph"><p>csync is a lightweight utility to synchronize files between two directories
@ -478,6 +756,7 @@ program which means you don&#8217;t need to be a superuser or administrator.</p>
Roaming Home Directories for Linux (see <a href="#X80">The PAM Module</a>).</p></div>
</div>
</div>
<div class="sect1">
<h2 id="_introduction">1. Introduction</h2>
<div class="sectionbody">
<div class="paragraph"><p>It is often the case that we have multiple copies (called replicas) of a
@ -492,10 +771,13 @@ left, we are done, and the replicas are identical. To resolve or handle
conflicts there are several algorithms available. They will be discussed
one of the following sections.</p></div>
</div>
</div>
<div class="sect1">
<h2 id="_basics">2. Basics</h2>
<div class="sectionbody">
<div class="paragraph"><p>This section describes some basics of file synchronization.</p></div>
<h3 id="_paths">2.1. Paths</h3><div style="clear:left"></div>
<div class="sect2">
<h3 id="_paths">2.1. Paths</h3>
<div class="paragraph"><p>A path normally refers to a point which contains a set of files which should be
synchronized. It is specified relative to the root of the replica locally, but
has to be absolute if you use a protocol. The path is just a sequence of names
@ -510,7 +792,9 @@ separated by <em>/</em>.</p></div>
</div>
<div class="paragraph"><p>csync always uses the absolute path on remote replicas. This could
<em>sftp://gladiac:secret@myserver/home/gladiac</em> for sftp.</p></div>
<h3 id="_what_is_an_update">2.2. What is an update?</h3><div style="clear:left"></div>
</div>
<div class="sect2">
<h3 id="_what_is_an_update">2.2. What is an update?</h3>
<div class="paragraph"><p>The contents of a path could be a file, a directory or a symbolic link
(symbolic links are not supported yet). To be more precise, if the path refers
to:</p></div>
@ -537,7 +821,9 @@ path gets compared with the record and if it has changed since the last
synchronization, we have an update. This is done by comparing the modification
or change (modification time of the metadata) time. This is the way how updates
are detected.</p></div>
<h3 id="_what_is_a_conflict">2.3. What is a conflict?</h3><div style="clear:left"></div>
</div>
<div class="sect2">
<h3 id="_what_is_a_conflict">2.3. What is a conflict?</h3>
<div class="paragraph"><p>A path is conflicting if it fulfills the following conditions:</p></div>
<div class="olist arabic"><ol class="arabic">
<li>
@ -557,6 +843,9 @@ its contents in are not identical.
</li>
</ol></div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_file_synchronization">3. File Synchronization</h2>
<div class="sectionbody">
<div class="paragraph"><p>The primary goal of the file synchronizer is correctness. It may change
@ -572,7 +861,8 @@ fulfill these goals.</p></div>
user interaction should be possible and it should be easy to understand the
process. The three phases are update detection, reconciliation and propagation.
These will be described in the following sections.</p></div>
<h3 id="_update_detection">3.1. Update detection</h3><div style="clear:left"></div>
<div class="sect2">
<h3 id="_update_detection">3.1. Update detection</h3>
<div class="paragraph"><p>There are different strategies for update detection. csync uses a state-based
modtime-inode update detector. This means it uses the modification time to
detect updates. It doesn&#8217;t require many resources. A record of each file is
@ -585,7 +875,9 @@ is marked as new.</p></div>
by the record we store in the statedb. If we don&#8217;t find the file by the name
in the database, we search for the inode number. If the inode number is found
then the file has been renamed.</p></div>
<h3 id="_reconciliation">3.2. Reconciliation</h3><div style="clear:left"></div>
</div>
<div class="sect2">
<h3 id="_reconciliation">3.2. Reconciliation</h3>
<div class="paragraph"><p>The most important component is the update detector, because the reconciler
depends on it. The correctness of reconciler is mandatory because it can damage
a filesystem. It decides which file:</p></div>
@ -613,20 +905,28 @@ or is <strong>deleted</strong>
</ul></div>
<div class="paragraph"><p>A wrong decision of the reconciler leads in most cases to a loss of data. So
there are several conditions which a file synchronizer has to follow.</p></div>
<div class="sect3">
<h4 id="_algorithms">3.2.1. Algorithms</h4>
<div class="paragraph"><p>For conflict resolution several different algorithms could be implemented. The
most common algorithms are the merge and the conflict algorithm. The first
is a batch algorithm and the second is one which needs user interaction.</p></div>
<div class="sect4">
<h5 id="_merge_algorithm">Merge algorithm</h5>
<div class="paragraph"><p>The merge algorithm is an algorithm which doesn&#8217;t need any user interaction. It
is simple and used for example by Microsoft for Roaming Profiles. If it detects
a conflict (the same file changed on both replicas) then it will use the most
recent file and overwrite the other. This means you can loose some data, but
normally you want the latest file.</p></div>
</div>
<div class="sect4">
<h5 id="_conflict_algorithm">Conflict algorithm</h5>
<div class="paragraph"><p>This is not implemented yet.</p></div>
<div class="paragraph"><p>If a file has a conflict the user has to decide which file should be used.</p></div>
<h3 id="_propagation">3.3. Propagation</h3><div style="clear:left"></div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_propagation">3.3. Propagation</h3>
<div class="paragraph"><p>The next instance of the file synchronizer is the propagator. It uses the
calculated records to apply them on the current replica.</p></div>
<div class="paragraph"><p>The propagator uses a two-phase-commit mechanism to simulate an atomic
@ -643,10 +943,13 @@ current state of the filesystem tree. This updated tree will be written as a
journal into the state database. It will be used during the update detection of
the next synchronization. See above for a description of the state database
during synchronization.</p></div>
<h3 id="_robustness">3.4. Robustness</h3><div style="clear:left"></div>
</div>
<div class="sect2">
<h3 id="_robustness">3.4. Robustness</h3>
<div class="paragraph"><p>This is a very important topic. The file synchronizer should not crash, and if
it has crashed, there should be no loss of data. To achieve this goal there are
several mechanisms which will be discussed in the following sections.</p></div>
<div class="sect3">
<h4 id="_crash_resistance">3.4.1. Crash resistance</h4>
<div class="paragraph"><p>The synchronization process can be interrupted by different events, this can
be:</p></div>
@ -692,6 +995,8 @@ until we overwrite it after a successful synchronization. Therefore, each
interrupted synchronization process is a partial sync and can be continued and
completed by simply running csync again. The only problem could be an error of
the filesystem, so we reach this invariant only approximately.</p></div>
</div>
<div class="sect3">
<h4 id="_transfer_errors">3.4.2. Transfer errors</h4>
<div class="paragraph"><p>With the Two-Phase-Commit we check the file size after the file has transferred
and we are able to detect transfer errors. A more robust approach would be a
@ -700,6 +1005,8 @@ add this in the future.</p></div>
<div class="paragraph"><p>Future filesystems, like btrfs, will help to compare checksums instead of the
filesize. This will make the synchronization safer. This does not imply that it
is unsafe now, but checksums are safer than simple filesize checks.</p></div>
</div>
<div class="sect3">
<h4 id="_database_loss">3.4.3. Database loss</h4>
<div class="paragraph"><p>It is possible that the state database could get corrupted. If this happens,
all files get evaluated. In this case the file synchronizer wont delete any
@ -709,12 +1016,19 @@ replica.</p></div>
forces an abort, the synchronizer is working on a copy of the database and will
use a Two-Phase-Commit to save it at the end.</p></div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_getting_started">4. Getting started</h2>
<div class="sectionbody">
<h3 id="_installing_csync">4.1. Installing csync</h3><div style="clear:left"></div>
<div class="sect2">
<h3 id="_installing_csync">4.1. Installing csync</h3>
<div class="paragraph"><p>See the <tt>README</tt> and <tt>INSTALL</tt> files for install prerequisites and
procedures. Packagers should take a look at <a href="#X90">Appendix A: Packager Notes</a>.</p></div>
<h3 id="_using_the_commandline_client">4.2. Using the commandline client</h3><div style="clear:left"></div>
</div>
<div class="sect2">
<h3 id="_using_the_commandline_client">4.2. Using the commandline client</h3>
<div class="paragraph"><p>The synopsis of the commandline client is</p></div>
<div class="literalblock">
<div class="content">
@ -726,6 +1040,7 @@ DESTINATION can be a local directory or a remote file server.</p></div>
<div class="content">
<pre><tt>csync /home/csync scheme://user:password@server:port/full/path</tt></pre>
</div></div>
<div class="sect3">
<h4 id="_examples">4.2.1. Examples</h4>
<div class="paragraph"><p>To synchronize two local directories:</p></div>
<div class="literalblock">
@ -753,7 +1068,10 @@ following way:</p></div>
</div></div>
<div class="paragraph"><p>The remote destination is supported by plugins. By default csync ships with smb
and sftp support. For more information, see the manpage of <tt>csync(1)</tt>.</p></div>
<h3 id="_exclude_lists">4.3. Exclude lists</h3><div style="clear:left"></div>
</div>
</div>
<div class="sect2">
<h3 id="_exclude_lists">4.3. Exclude lists</h3>
<div class="paragraph"><p>csync provides exclude lists with simple shell wildcard patterns. There is a
global exclude list, which is normally located in
<em>/etc/csync/csync_exclude.conf</em> and it has already some sane defaults. If you
@ -762,56 +1080,18 @@ This file will be <em>~/.csync/csync_exclude.conf</em>. csync considers both
configuration files and an additional one if you specify it.</p></div>
<div class="paragraph"><p>The entries in the file are newline separated. Use
<em>/etc/csync/csync_exclude.conf</em> as an example.</p></div>
<h3 id="_debug_messages_and_dry_run">4.4. Debug messages and dry run</h3><div style="clear:left"></div>
<div class="paragraph"><p>For log messages csync uses log4c. It is a logging mechanism which uses debug
levels and categories. There is a config file where you can specify the debug
level for each component. It is located at <em>~/.csync/csync_log.conf</em>.</p></div>
<div class="paragraph"><p>Available debug priorities are:</p></div>
<div class="ulist"><ul>
<li>
<p>
trace
</p>
</li>
<li>
<p>
debug
</p>
</li>
<li>
<p>
info
</p>
</li>
<li>
<p>
warn
</p>
</li>
<li>
<p>
error
</p>
</li>
<li>
<p>
fatal
</p>
</li>
<li>
<p>
none
</p>
</li>
</ul></div>
<div class="paragraph"><p>A more detailed description can be found at the
<a href="http://log4c.sourceforge.net/">log4c homepage</a>. A good introduction can
be found <a href="http://logging.apache.org/log4j/1.2/manual.html">here</a>.</p></div>
</div>
<div class="sect2">
<h3 id="_debug_messages_and_dry_run">4.4. Debug messages and dry run</h3>
<div class="paragraph"><p>By default the csync client logs to stderr and you can increase the debug
level with a commandline options.</p></div>
<div class="paragraph"><p>To simulate a run of the file synchronizer, you should set the priority to
<em>debug</em> for the categories <em>csync.updater</em> and <em>csync.reconciler</em> in the config
file <em>~/.csync/csync_log.conf</em>. Then run csync with the <em>--dry-run</em> option.
This will only run update detection and reconciliation.</p></div>
<h3 id="X80">4.5. The PAM module</h3><div style="clear:left"></div>
</div>
<div class="sect2">
<h3 id="X80">4.5. The PAM module</h3>
<div class="paragraph"><p>pam_csync is a PAM module to provide roaming home directories for a user
session. This module is aimed at environments with central file servers where a
user wishes to store his home directory. The Authentication Module verifies the
@ -819,14 +1099,20 @@ identity of a user and triggers a synchronization with the server on the first
login and the last logout. More information can be found in the manpage of the
module pam_csync(8) or pam itself pam(8).</p></div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="X90">5. Appendix A: Packager Notes</h2>
<div class="sectionbody">
<div class="paragraph"><p>Read the <tt>README</tt>, <tt>INSTALL</tt> and <tt>FAQ</tt> files (in the distribution root
directory).</p></div>
</div>
</div>
</div>
<div id="footnotes"><hr /></div>
<div id="footer">
<div id="footer-text">
Last updated 2012-10-07 12:15:24 CEST
Last updated 2012-10-29 12:05:41 CET
</div>
</div>
</body>

View file

@ -41,15 +41,11 @@ set(CSYNC_LINK_LIBRARIES
${SQLITE3_LIBRARIES}
)
if(LOG4C_FOUND)
list(APPEND CSYNC_PRIVATE_INCLUDE_DIRS ${LOG4C_INCLUDE_DIRS})
list(APPEND CSYNC_LINK_LIBRARIES ${LOG4C_LIBRARIES})
endif()
set(csync_SRCS
csync.c
csync_config.c
csync_exclude.c
csync_log.c
csync_statedb.c
csync_dbtree.c
csync_time.c

View file

@ -1,7 +1,7 @@
/*
* libcsync -- a library to sync a directory with another
*
* Copyright (c) 2008 by Andreas Schneider <mail@cynapses.org>
* Copyright (c) 2008-2012 by Andreas Schneider <asn@cryptomilk.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -49,7 +49,6 @@
#include "vio/csync_vio.h"
#define CSYNC_LOG_CATEGORY_NAME "csync.api"
#include "csync_log.h"
static int _key_cmp(const void *key, const void *data) {
@ -155,7 +154,6 @@ int csync_create(CSYNC **csync, const char *local, const char *remote) {
int csync_init(CSYNC *ctx) {
int rc;
time_t timediff = -1;
char *log = NULL;
char *exclude = NULL;
char *lock = NULL;
char *config = NULL;
@ -172,35 +170,11 @@ int csync_init(CSYNC *ctx) {
return 1;
}
/* load log file */
if (csync_log_init() < 0) {
ctx->error_code = CSYNC_ERR_LOG;
fprintf(stderr, "csync_init: logger init failed\n");
return -1;
}
/* create dir if it doesn't exist */
if (! c_isdir(ctx->options.config_dir)) {
c_mkdirs(ctx->options.config_dir, 0700);
}
if (asprintf(&log, "%s/%s", ctx->options.config_dir, CSYNC_LOG_FILE) < 0) {
ctx->error_code = CSYNC_ERR_UNSPEC;
rc = -1;
goto out;
}
/* load log if it exists */
if (c_isfile(log)) {
csync_log_load(log);
} else {
#ifndef _WIN32
if (c_copy(SYSCONFDIR "/ocsync/" CSYNC_LOG_FILE, log, 0644) == 0) {
csync_log_load(log);
}
#endif
}
/* create lock file */
if (asprintf(&lock, "%s/%s", ctx->options.config_dir, CSYNC_LOCK_FILE) < 0) {
ctx->error_code = CSYNC_ERR_UNSPEC;
@ -209,7 +183,7 @@ int csync_init(CSYNC *ctx) {
}
#ifndef _WIN32
if (csync_lock(lock) < 0) {
if (csync_lock(ctx, lock) < 0) {
ctx->error_code = CSYNC_ERR_LOCK;
rc = -1;
goto out;
@ -236,7 +210,7 @@ int csync_init(CSYNC *ctx) {
if (csync_exclude_load(ctx, exclude) < 0) {
strerror_r(errno, errbuf, sizeof(errbuf));
CSYNC_LOG(CSYNC_LOG_PRIORITY_INFO, "Could not load %s - %s", exclude,
CSYNC_LOG(CSYNC_LOG_PRIORITY_WARN, "Could not load %s - %s", exclude,
errbuf);
}
SAFE_FREE(exclude);
@ -368,7 +342,6 @@ retry_vio_init:
rc = 0;
out:
SAFE_FREE(log);
SAFE_FREE(lock);
SAFE_FREE(exclude);
SAFE_FREE(config);
@ -385,7 +358,7 @@ int csync_update(CSYNC *ctx) {
}
ctx->error_code = CSYNC_ERR_NONE;
csync_memstat_check();
csync_memstat_check(ctx);
/* update detection for local replica */
csync_gettime(&start);
@ -399,7 +372,7 @@ int csync_update(CSYNC *ctx) {
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG,
"Update detection for local replica took %.2f seconds walking %zu files.",
c_secdiff(finish, start), c_rbtree_size(ctx->local.tree));
csync_memstat_check();
csync_memstat_check(ctx);
if (rc < 0) {
if(ctx->error_code == CSYNC_ERR_NONE)
@ -432,7 +405,7 @@ int csync_update(CSYNC *ctx) {
"Update detection for remote replica took %.2f seconds "
"walking %zu files.",
c_secdiff(finish, start), c_rbtree_size(ctx->remote.tree));
csync_memstat_check();
csync_memstat_check(ctx);
if (rc < 0) {
if(ctx->error_code == CSYNC_ERR_NONE )
@ -564,13 +537,14 @@ static int _csync_treewalk_visitor(void *obj, void *data) {
cur = (csync_file_stat_t *) obj;
ctx = (CSYNC *) data;
if (!(ctx && obj && data)) {
ctx->error_code = CSYNC_ERR_PARAM;
return -1;
}
ctx->error_code = CSYNC_ERR_NONE;
twctx = (_csync_treewalk_context*) ctx->userdata;
twctx = (_csync_treewalk_context*) ctx->callbacks.userdata;
if (twctx == NULL) {
ctx->error_code = CSYNC_ERR_PARAM;
return -1;
@ -622,17 +596,17 @@ static int _csync_walk_tree(CSYNC *ctx, c_rbtree_t *tree, csync_treewalk_visit_f
return rc;
}
tw_ctx.userdata = ctx->userdata;
tw_ctx.userdata = ctx->callbacks.userdata;
tw_ctx.user_visitor = visitor;
tw_ctx.instruction_filter = filter;
ctx->userdata = &tw_ctx;
ctx->callbacks.userdata = &tw_ctx;
rc = c_rbtree_walk(tree, (void*) ctx, _csync_treewalk_visitor);
if( rc < 0 )
ctx->error_code = CSYNC_ERR_TREE;
ctx->userdata = tw_ctx.userdata;
ctx->callbacks.userdata = tw_ctx.userdata;
return rc;
}
@ -727,13 +701,10 @@ int csync_destroy(CSYNC *ctx) {
#ifndef _WIN32
/* remove the lock file */
if (asprintf(&lock, "%s/%s", ctx->options.config_dir, CSYNC_LOCK_FILE) > 0) {
csync_lock_remove(lock);
csync_lock_remove(ctx, lock);
}
#endif
/* stop logging */
csync_log_fini();
/* destroy the rbtrees */
if (c_rbtree_size(ctx->local.tree) > 0) {
c_rbtree_destroy(ctx->local.tree, _tree_destructor);
@ -860,7 +831,40 @@ int csync_set_auth_callback(CSYNC *ctx, csync_auth_callback cb) {
return -1;
}
ctx->auth_callback = cb;
ctx->callbacks.auth_function = cb;
return 0;
}
int csync_set_log_verbosity(CSYNC *ctx, int verbosity) {
if (ctx == NULL || verbosity < 0) {
return -1;
}
ctx->options.log_verbosity = verbosity;
return 0;
}
int csync_get_log_verbosity(CSYNC *ctx) {
if (ctx == NULL) {
return -1;
}
return ctx->options.log_verbosity;
}
int csync_set_log_callback(CSYNC *ctx, csync_log_callback cb) {
if (ctx == NULL || cb == NULL) {
return -1;
}
if (ctx->status & CSYNC_STATUS_INIT) {
fprintf(stderr, "This function must be called before initialization.");
return -1;
}
ctx->callbacks.log_function = cb;
return 0;
}
@ -880,7 +884,7 @@ void *csync_get_userdata(CSYNC *ctx) {
}
ctx->error_code = CSYNC_ERR_NONE;
return ctx->userdata;
return ctx->callbacks.userdata;
}
int csync_set_userdata(CSYNC *ctx, void *userdata) {
@ -889,7 +893,7 @@ int csync_set_userdata(CSYNC *ctx, void *userdata) {
}
ctx->error_code = CSYNC_ERR_NONE;
ctx->userdata = userdata;
ctx->callbacks.userdata = userdata;
return 0;
}
@ -900,7 +904,15 @@ csync_auth_callback csync_get_auth_callback(CSYNC *ctx) {
}
ctx->error_code = CSYNC_ERR_NONE;
return ctx->auth_callback;
return ctx->callbacks.auth_function;
}
csync_log_callback csync_get_log_callback(CSYNC *ctx) {
if (ctx == NULL) {
return NULL;
}
return ctx->callbacks.log_function;
}
int csync_set_status(CSYNC *ctx, int status) {

View file

@ -1,7 +1,7 @@
/*
* libcsync -- a library to sync a directory with another
*
* Copyright (c) 2006-2008 by Andreas Schneider <mail@cynapses.org>
* Copyright (c) 2006-2012 by Andreas Schneider <asn@cryptomilk.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -69,9 +69,6 @@ extern "C" {
#define CSYNC_EXCLUDE_FILE "ocsync_exclude.conf"
#define CSYNC_LOCK_FILE "lock"
typedef int (*csync_auth_callback) (const char *prompt, char *buf, size_t len,
int echo, int verify, void *userdata);
enum csync_error_codes_e {
CSYNC_ERR_NONE = 0,
CSYNC_ERR_LOG,
@ -159,6 +156,15 @@ typedef struct csync_tree_walk_file_s TREE_WALK_FILE;
*/
typedef struct csync_s CSYNC;
typedef int (*csync_auth_callback) (const char *prompt, char *buf, size_t len,
int echo, int verify, void *userdata);
typedef void (*csync_log_callback) (CSYNC *ctx,
int verbosity,
const char *function,
const char *buffer,
void *userdata);
/**
* @brief Allocate a csync context.
*
@ -352,6 +358,47 @@ csync_auth_callback csync_get_auth_callback(CSYNC *ctx);
*/
int csync_set_auth_callback(CSYNC *ctx, csync_auth_callback cb);
/**
* @brief Set the log verbosity.
*
* @param ctx The csync context.
*
* @param[in] verbosity The log verbosity.
*
* @return 0 on success, < 0 if an error occured.
*/
int csync_set_log_verbosity(CSYNC *ctx, int verbosity);
/**
* @brief Get the log verbosity
*
* @param[in] ctx The csync context to ask for the log verbosity.
*
* @return The log verbosity, -1 on error.
*/
int csync_get_log_verbosity(CSYNC *ctx);
/**
* @brief Get the logging callback set.
*
* @param ctx The csync context.
*
* @return The logging callback set or NULL if an error
* occured.
*/
csync_log_callback csync_get_log_callback(CSYNC *ctx);
/**
* @brief Set the logging callback.
*
* @param ctx The csync context.
*
* @param cb The logging callback.
*
* @return 0 on success, less than 0 if an error occured.
*/
int csync_set_log_callback(CSYNC *ctx, csync_log_callback cb);
/**
* @brief Get the path of the statedb file used.
*

View file

@ -34,7 +34,7 @@
#define CSYNC_LOG_CATEGORY_NAME "csync.config"
#include "csync_log.h"
static int _csync_config_copy_default (const char *config) {
static int _csync_config_copy_default (CSYNC *ctx, const char *config) {
int re = 0;
#ifdef _WIN32
/* For win32, try to copy the conf file from the directory from where the app was started. */
@ -119,7 +119,7 @@ int csync_config_load(CSYNC *ctx, const char *config) {
SAFE_FREE(home);
/* Still install the default one if nothing is there. */
if( ! c_isfile(config)) {
if (_csync_config_copy_default(config) < 0) {
if (_csync_config_copy_default(ctx, config) < 0) {
return -1;
}
}

View file

@ -41,7 +41,7 @@
#define CSYNC_LOG_CATEGORY_NAME "csync.lock"
#include "csync_log.h"
static int _csync_lock_create(const char *lockfile) {
static int _csync_lock_create(CSYNC *ctx, const char *lockfile) {
int fd = -1;
pid_t pid = 0;
int rc = -1;
@ -121,7 +121,7 @@ out:
return rc;
}
static pid_t _csync_lock_read(const char *lockfile) {
static pid_t _csync_lock_read(CSYNC *ctx, const char *lockfile) {
char errbuf[256] = {0};
char buf[8] = {0};
long int tmp;
@ -180,22 +180,22 @@ static pid_t _csync_lock_read(const char *lockfile) {
return pid;
}
int csync_lock(const char *lockfile) {
int csync_lock(CSYNC *ctx, const char *lockfile) {
/* Check if lock already exists. */
if (_csync_lock_read(lockfile) > 0) {
if (_csync_lock_read(ctx, lockfile) > 0) {
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Aborting, another synchronization process is running.");
return -1;
}
CSYNC_LOG(CSYNC_LOG_PRIORITY_INFO, "Creating lock file: %s", lockfile);
return _csync_lock_create(lockfile);
return _csync_lock_create(ctx, lockfile);
}
void csync_lock_remove(const char *lockfile) {
void csync_lock_remove(CSYNC *ctx, const char *lockfile) {
char errbuf[256] = {0};
/* You can't remove the lock if it is from another process */
if (_csync_lock_read(lockfile) == getpid()) {
if (_csync_lock_read(ctx, lockfile) == getpid()) {
CSYNC_LOG(CSYNC_LOG_PRIORITY_DEBUG, "Removing lock file: %s", lockfile);
if (unlink(lockfile) < 0) {
strerror_r(errno, errbuf, sizeof(errbuf));

View file

@ -21,6 +21,8 @@
#ifndef _CSYNC_LOCK_H
#define _CSYNC_LOCK_H
#include "csync.h"
/**
* @file csync_lock.h
*
@ -45,7 +47,7 @@
* @return 0 if the lock was successfull, less than 0 if the lock file
* couldn't be created or if it is already locked.
*/
int csync_lock(const char *lockfile);
int csync_lock(CSYNC *ctx, const char *lockfile);
/**
* @brief Remove the lockfile
@ -55,7 +57,7 @@ int csync_lock(const char *lockfile);
*
* @param lockfile The lock file to remove.
*/
void csync_lock_remove(const char *lockfile);
void csync_lock_remove(CSYNC *ctx, const char *lockfile);
/**
* }@

120
src/csync_log.c Normal file
View file

@ -0,0 +1,120 @@
/*
* libcsync -- a library to sync a directory with another
*
* Copyright (c) 2012 by Andreas Schneider <asn@cryptomilk.org>
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "config.h"
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#ifndef _WIN32
#include <sys/time.h>
#else
#include <sys/utime.h>
#endif
#include <time.h>
#include "csync_private.h"
#include "csync_log.h"
static int current_timestring(int hires, char *buf, size_t len)
{
char tbuf[64];
struct timeval tv;
struct tm *tm;
time_t t;
gettimeofday(&tv, NULL);
t = (time_t) tv.tv_sec;
tm = localtime(&t);
if (tm == NULL) {
return -1;
}
if (hires) {
strftime(tbuf, sizeof(tbuf) - 1, "%Y/%m/%d %H:%M:%S", tm);
snprintf(buf, len, "%s.%06ld", tbuf, tv.tv_usec);
} else {
strftime(tbuf, sizeof(tbuf) - 1, "%Y/%m/%d %H:%M:%S", tm);
snprintf(buf, len, "%s", tbuf);
}
return 0;
}
static void csync_log_stderr(int verbosity,
const char *function,
const char *buffer)
{
char date[64] = {0};
int rc;
rc = current_timestring(1, date, sizeof(date));
if (rc == 0) {
fprintf(stderr, "[%s, %d] %s:", date, verbosity, function);
} else {
fprintf(stderr, "[%d] %s", verbosity, function);
}
fprintf(stderr, " %s\n", buffer);
}
static void csync_log_function(CSYNC *ctx,
int verbosity,
const char *function,
const char *buffer)
{
csync_log_callback log_fn = csync_get_log_callback(ctx);
if (log_fn) {
char buf[1024];
snprintf(buf, sizeof(buf), "%s: %s", function, buffer);
log_fn(ctx,
verbosity,
function,
buf,
csync_get_userdata(ctx));
return;
}
csync_log_stderr(verbosity, function, buffer);
}
void csync_log(CSYNC *ctx,
int verbosity,
const char *function,
const char *format, ...)
{
char buffer[1024];
va_list va;
if (ctx == NULL) {
return;
}
if (verbosity <= csync_get_log_verbosity(ctx)) {
va_start(va, format);
vsnprintf(buffer, sizeof(buffer), format, va);
va_end(va);
csync_log_function(ctx, verbosity, function, buffer);
}
}

View file

@ -1,7 +1,7 @@
/*
* libcsync -- a library to sync a directory with another
*
* Copyright (c) 2006 by Andreas Schneider <mail@cynapses.org>
* Copyright (c) 2006-2012 by Andreas Schneider <asn@cryptomilk.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -32,23 +32,6 @@
#ifndef _CSYNC_LOG_H
#define _CSYNC_LOG_H
#include "config.h"
#ifdef CSYNC_TEST
#undef WITH_LOG4C
#endif
#ifdef WITH_LOG4C
#include "log4c.h"
#else
#include <stdarg.h>
#include <stdio.h>
#endif
#ifndef CSYNC_LOG_CATEGORY_NAME
#define CSYNC_LOG_CATEGORY_NAME "root"
#endif
/* GCC have printf type attribute check. */
#ifdef __GNUC__
#define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
@ -56,14 +39,21 @@
#define PRINTF_ATTRIBUTE(a,b)
#endif /* __GNUC__ */
/*#define CSYNC_LOG(priority, fmt, ...) \
csync_log((char *) CSYNC_LOG_CATEGORY_NAME, priority, fmt, ## __VA_ARGS__)*/
/*
* fix hundreds of these warnings:
* csync.c:272:75: warning: ISO C99 requires rest arguments to be used [enabled by default]
* The ## token in combination with __VA_ARGS__ is a gcc extension that's not part of ISO C99
* http://stackoverflow.com/questions/4100746/suppressing-iso-c99-requires-rest-arguments-to-be-used
*/
enum csync_log_priority_e {
CSYNC_LOG_PRIORITY_NOLOG = 0,
CSYNC_LOG_PRIORITY_FATAL,
CSYNC_LOG_PRIORITY_ALERT,
CSYNC_LOG_PRIORITY_CRIT,
CSYNC_LOG_PRIORITY_ERROR,
CSYNC_LOG_PRIORITY_WARN,
CSYNC_LOG_PRIORITY_NOTICE,
CSYNC_LOG_PRIORITY_INFO,
CSYNC_LOG_PRIORITY_DEBUG,
CSYNC_LOG_PRIORITY_TRACE,
CSYNC_LOG_PRIORITY_NOTSET,
CSYNC_LOG_PRIORITY_UNKNOWN,
};
#ifdef LOG_TO_CALLBACK
#define CSYNC_LOG(priority, ...) \
csync_log_cb((char *) CSYNC_LOG_CATEGORY_NAME, priority, __VA_ARGS__)
@ -72,122 +62,14 @@
csync_log((char *) CSYNC_LOG_CATEGORY_NAME, priority, __VA_ARGS__)
#endif
#ifdef WITH_LOG4C
#define CSYNC_LOG_PRIORITY_FATAL LOG4C_PRIORITY_FATAL
#define CSYNC_LOG_PRIORITY_ALERT LOG4C_PRIORITY_ALERT
#define CSYNC_LOG_PRIORITY_CRIT LOG4C_PRIORITY_CRIT
#define CSYNC_LOG_PRIORITY_ERROR LOG4C_PRIORITY_ERROR
#define CSYNC_LOG_PRIORITY_WARN LOG4C_PRIORITY_WARN
#define CSYNC_LOG_PRIORITY_NOTICE LOG4C_PRIORITY_NOTICE
#define CSYNC_LOG_PRIORITY_INFO LOG4C_PRIORITY_INFO
#define CSYNC_LOG_PRIORITY_DEBUG LOG4C_PRIORITY_DEBUG
#define CSYNC_LOG_PRIORITY_TRACE LOG4C_PRIORITY_TRACE
#define CSYNC_LOG_PRIORITY_NOTSET LOG4C_PRIORITY_NOTSET
#define CSYNC_LOG_PRIORITY_UNKNOWN LOG4C_PRIORITY_UNKNOWN
#else
#define LOG4C_INLINE inline
#define CSYNC_LOG_PRIORITY_FATAL 000
#define CSYNC_LOG_PRIORITY_ALERT 100
#define CSYNC_LOG_PRIORITY_CRIT 200
#define CSYNC_LOG_PRIORITY_ERROR 300
#define CSYNC_LOG_PRIORITY_WARN 500
#define CSYNC_LOG_PRIORITY_NOTICE 500
#define CSYNC_LOG_PRIORITY_INFO 600
#define CSYNC_LOG_PRIORITY_DEBUG 700
#define CSYNC_LOG_PRIORITY_TRACE 800
#define CSYNC_LOG_PRIORITY_NOTSET 900
#define CSYNC_LOG_PRIORITY_UNKNOWN 1000
#endif
static LOG4C_INLINE void csync_log(char *catName, int a_priority,
const char* a_format,...) PRINTF_ATTRIBUTE(3, 4);
/**
* @brief The constructor of the logging mechanism
*
* @return 0 on success, less than 0 if an error occured.
*/
static LOG4C_INLINE int csync_log_init() {
#ifdef WITH_LOG4C
return log4c_init();
#else
return 0;
#endif
}
/**
* @brief Load resource configuration file
*
* @param Path to the file to load
*
* @return 0 on success, less than 0 if an error occured.
**/
static LOG4C_INLINE int csync_log_load(const char *path){
#ifdef WITH_LOG4C
return log4c_load(path);
#else
if (path == NULL) {
return 0;
}
return 0;
#endif
}
/**
* @brief The destructor of the logging mechanism
*
* @return 0 on success, less than 0 if an error occured.
*/
static LOG4C_INLINE int csync_log_fini(){
#ifdef WITH_LOG4C
return log4c_fini();
#else
return 0;
#endif
}
static LOG4C_INLINE int csync_log_setappender(char *catName, char *appName) {
#ifdef WITH_LOG4C
log4c_category_set_appender(log4c_category_get(catName),
log4c_appender_get(appName));
return 0;
#else
if (catName == NULL || appName == NULL) {
return 0;
}
return 0;
#endif
}
static LOG4C_INLINE void csync_log(char *catName, int a_priority,
const char* a_format,...) {
#ifdef WITH_LOG4C
const log4c_category_t* a_category = log4c_category_get(catName);
if (log4c_category_is_priority_enabled(a_category, a_priority)) {
va_list va;
va_start(va, a_format);
log4c_category_vlog(a_category, a_priority, a_format, va);
va_end(va);
}
#else
/* On Apple, all stderr & stdout go to Apple System Log (ASL) by default.
* Thats certainly too much at the moment.
*/
#ifndef __APPLE__
va_list va;
va_start(va, a_format);
if (a_priority > 0) {
printf("%s - ", catName);
}
vprintf(a_format, va);
va_end(va);
printf("\n");
#endif
#endif
}
void csync_log(CSYNC *ctx,
int verbosity,
const char *function,
const char *format, ...) PRINTF_ATTRIBUTE(4, 5);
/**
* }@
*/
#endif /* _CSYNC_LOG_H */
/* vim: set ft=c.doxygen ts=8 sw=2 et cindent: */
/* vim: set ft=c.doxygen ts=4 sw=4 et cindent: */

View file

@ -1,7 +1,7 @@
/*
* libcsync -- a library to sync a directory with another
*
* Copyright (c) 2006 by Andreas Schneider <mail@cynapses.org>
* Copyright (c) 2006-2012 by Andreas Schneider <asn@cryptomilk.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -79,8 +79,11 @@ enum csync_replica_e {
* @brief csync public structure
*/
struct csync_s {
csync_auth_callback auth_callback;
void *userdata;
struct {
csync_auth_callback auth_function;
csync_log_callback log_function;
void *userdata;
} callbacks;
c_strlist_t *excludes;
struct {
@ -123,6 +126,7 @@ struct csync_s {
bool with_conflict_copys;
bool local_only_mode;
bool remote_push_atomar;
int log_verbosity;
} options;
struct {

View file

@ -502,7 +502,7 @@ out:
return rc;
}
static int _backup_path(char** duri, const char* uri, const char* path)
static int _backup_path(CSYNC *ctx, char** duri, const char* uri, const char* path)
{
int rc=0;
C_PATHINFO *info=NULL;
@ -552,7 +552,7 @@ static int _csync_backup_file(CSYNC *ctx, csync_file_stat_t *st) {
goto out;
}
if ( _backup_path(&duri, ctx->remote.uri,st->path) < 0) {
if (_backup_path(ctx, &duri, ctx->remote.uri,st->path) < 0) {
rc = -1;
goto out;
}
@ -564,7 +564,7 @@ static int _csync_backup_file(CSYNC *ctx, csync_file_stat_t *st) {
goto out;
}
if ( _backup_path(&duri, ctx->local.uri, st->path) < 0) {
if ( _backup_path(ctx, &duri, ctx->local.uri, st->path) < 0) {
rc = -1;
goto out;
}

View file

@ -74,8 +74,8 @@ static void _csync_win32_hide_file( const char *file ) {
#endif
}
static int _csync_statedb_check(const char *statedb) {
int fd = -1;
static int _csync_statedb_check(CSYNC *ctx, const char *statedb) {
int fd = -1, rc;
ssize_t r;
char buf[BUF_SIZE] = {0};
sqlite3 *db = NULL;
@ -113,11 +113,13 @@ static int _csync_statedb_check(const char *statedb) {
}
/* create database */
if (sqlite3_open(statedb, &db) == SQLITE_OK) {
rc = sqlite3_open(statedb, &db);
if (rc == SQLITE_OK) {
sqlite3_close(db);
_csync_win32_hide_file(statedb);
return 0;
}
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "%s %s", sqlite3_errmsg(db), statedb);
sqlite3_close(db);
return -1;
@ -185,7 +187,7 @@ int csync_statedb_load(CSYNC *ctx, const char *statedb) {
/* csync_statedb_check tries to open the statedb and creates it in case
* its not there.
*/
if (_csync_statedb_check(statedb) < 0) {
if (_csync_statedb_check(ctx, statedb) < 0) {
rc = -1;
goto out;
}

View file

@ -82,7 +82,7 @@ const char *csync_instruction_str(enum csync_instructions_e instr)
}
void csync_memstat_check(void) {
void csync_memstat_check(CSYNC *ctx) {
int s = 0;
struct csync_memstat_s m;
FILE* fp;

View file

@ -27,7 +27,7 @@
const char *csync_instruction_str(enum csync_instructions_e instr);
void csync_memstat_check(void);
void csync_memstat_check(CSYNC *ctx);
int csync_merge_file_trees(CSYNC *ctx);

View file

@ -35,6 +35,7 @@ add_cmocka_test(check_std_c_time std_tests/check_std_c_time.c ${TEST_TARGET_LIBR
add_cmocka_test(check_csync_create csync_tests/check_csync_create.c ${TEST_TARGET_LIBRARIES})
add_cmocka_test(check_csync_lock csync_tests/check_csync_lock.c ${TEST_TARGET_LIBRARIES})
add_cmocka_test(check_csync_log csync_tests/check_csync_log.c ${TEST_TARGET_LIBRARIES})
add_cmocka_test(check_csync_config csync_tests/check_csync_config.c ${TEST_TARGET_LIBRARIES})
add_cmocka_test(check_csync_exclude csync_tests/check_csync_exclude.c ${TEST_TARGET_LIBRARIES})
add_cmocka_test(check_csync_statedb_load csync_tests/check_csync_statedb_load.c ${TEST_TARGET_LIBRARIES})

View file

@ -41,10 +41,10 @@ static void teardown(void **state) {
static void check_csync_config_copy_default(void **state)
{
CSYNC *csync = *state;
int rc;
(void) state; /* unused */
rc = _csync_config_copy_default(TESTCONF);
rc = _csync_config_copy_default(csync, TESTCONF);
assert_int_equal(rc, 0);
}

View file

@ -38,15 +38,15 @@ static void check_csync_lock(void **state)
(void) state; /* unused */
rc = csync_lock(TEST_LOCK);
rc = csync_lock(NULL, TEST_LOCK);
assert_int_equal(rc, 0);
assert_true(c_isfile(TEST_LOCK));
rc = csync_lock(TEST_LOCK);
rc = csync_lock(NULL, TEST_LOCK);
assert_int_equal(rc, -1);
csync_lock_remove(TEST_LOCK);
csync_lock_remove(NULL, TEST_LOCK);
assert_false(c_isfile(TEST_LOCK));
}
@ -57,7 +57,7 @@ static void check_csync_lock_content(void **state)
(void) state; /* unused */
rc = csync_lock(TEST_LOCK);
rc = csync_lock(NULL, TEST_LOCK);
assert_int_equal(rc, 0);
assert_true(c_isfile(TEST_LOCK));
@ -78,7 +78,7 @@ static void check_csync_lock_content(void **state)
assert_int_equal(pid, getpid());
csync_lock_remove(TEST_LOCK);
csync_lock_remove(NULL, TEST_LOCK);
assert_false(c_isfile(TEST_LOCK));
}

View file

@ -0,0 +1,130 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "torture.h"
#include "csync.h"
#include "csync_log.c"
static void setup(void **state) {
CSYNC *csync;
int rc;
rc = system("mkdir -p /tmp/check_csync1");
assert_int_equal(rc, 0);
rc = system("mkdir -p /tmp/check_csync2");
assert_int_equal(rc, 0);
rc = csync_create(&csync, "/tmp/check_csync1", "/tmp/check_csync2");
assert_int_equal(rc, 0);
rc = csync_set_config_dir(csync, "/tmp/check_csync");
assert_int_equal(rc, 0);
*state = csync;
}
static void teardown(void **state) {
CSYNC *csync = *state;
int rc;
rc = csync_destroy(csync);
rc = system("rm -rf /tmp/check_csync");
assert_int_equal(rc, 0);
rc = system("rm -rf /tmp/check_csync1");
assert_int_equal(rc, 0);
rc = system("rm -rf /tmp/check_csync2");
assert_int_equal(rc, 0);
*state = NULL;
}
static void check_log_callback(CSYNC *ctx,
int verbosity,
const char *function,
const char *buffer,
void *userdata)
{
int rc;
assert_non_null(ctx);
assert_true(verbosity >= 0);
assert_non_null(function);
assert_false(function[0] == '\0');
assert_non_null(buffer);
assert_false(buffer[0] == '\0');
(void) userdata; /* unused */
rc = system("touch /tmp/check_csync1/cb_called");
assert_int_equal(rc, 0);
}
static void check_set_log_verbosity(void **state)
{
CSYNC *csync = *state;
int rc;
rc = csync_set_log_verbosity(NULL, 1);
assert_int_equal(rc, -1);
rc = csync_set_log_verbosity(csync, -5);
assert_int_equal(rc, -1);
rc = csync_set_log_verbosity(csync, 5);
assert_int_equal(rc, 0);
rc = csync_get_log_verbosity(csync);
assert_int_equal(rc, 5);
}
static void check_set_auth_callback(void **state)
{
csync_log_callback log_fn;
CSYNC *csync = *state;
int rc;
rc = csync_set_log_callback(csync, NULL);
assert_int_equal(rc, -1);
rc = csync_set_log_callback(csync, check_log_callback);
assert_int_equal(rc, 0);
log_fn = csync_get_log_callback(csync);
assert_non_null(log_fn);
assert_true(log_fn == &check_log_callback);
}
static void check_logging(void **state)
{
CSYNC *csync = *state;
int rc;
struct stat sb;
rc = csync_set_log_verbosity(csync, 1);
assert_int_equal(rc, 0);
rc = csync_set_log_callback(csync, check_log_callback);
assert_int_equal(rc, 0);
csync_log(csync, 1, __FUNCTION__, "rc = %d", rc);
rc = lstat("/tmp/check_csync1/cb_called", &sb);
assert_int_equal(rc, 0);
}
int torture_run_tests(void)
{
const UnitTest tests[] = {
unit_test_setup_teardown(check_set_log_verbosity, setup, teardown),
unit_test_setup_teardown(check_set_auth_callback, setup, teardown),
unit_test_setup_teardown(check_logging, setup, teardown),
};
return run_tests(tests);
}

View file

@ -51,20 +51,20 @@ static void check_csync_statedb_check(void **state)
/* old db */
rc = system("echo \"SQLite format 2\" > /tmp/check_csync1/test.db");
assert_int_equal(rc, 0);
rc = _csync_statedb_check(TESTDB);
rc = _csync_statedb_check(NULL, TESTDB);
assert_int_equal(rc, 0);
/* db already exists */
rc = _csync_statedb_check(TESTDB);
rc = _csync_statedb_check(NULL, TESTDB);
assert_int_equal(rc, 0);
/* no db exists */
rc = system("rm -f /tmp/check_csync1/test.db");
assert_int_equal(rc, 0);
rc = _csync_statedb_check(TESTDB);
rc = _csync_statedb_check(NULL, TESTDB);
assert_int_equal(rc, 0);
rc = _csync_statedb_check("/tmp/check_csync1/");
rc = _csync_statedb_check(NULL, "/tmp/check_csync1/");
assert_int_equal(rc, -1);
rc = system("rm -rf /tmp/check_csync1");

View file

@ -19,7 +19,7 @@ static void check_csync_memstat(void **state)
{
(void) state; /* unused */
csync_memstat_check();
csync_memstat_check(NULL);
}
int torture_run_tests(void)

View file

@ -25,39 +25,6 @@
fun:suite_create
}
### LOG4C
{
Still reacheable memory in log4c
Memcheck:Leak
fun:calloc
fun:sd_hash_*
}
{
Still reacheable memory in log4c
Memcheck:Leak
fun:calloc
fun:sd_factory_*
}
{
Still reacheable memory in log4c
Memcheck:Leak
fun:calloc
fun:log4c_category_*
fun:sd_factory_*
}
{
Still reacheable memory in log4c
Memcheck:Leak
fun:malloc
fun:strdup
fun:sd_factory_*
fun:log4c_category_*
}
### SQLITE3
{