improves config error reporting and adds check (check-config) command + dav-sync no longer aborts on missing sync.xml

Fri, 11 Nov 2016 15:03:19 +0100

author
Mike Becker <universe@uap-core.de>
date
Fri, 11 Nov 2016 15:03:19 +0100
changeset 252
6b8e287269fc
parent 251
7534cb97b9ab
child 253
1d2be1b31e70

improves config error reporting and adds check (check-config) command + dav-sync no longer aborts on missing sync.xml

dav/config.c file | annotate | diff | comparison | revisions
dav/config.h file | annotate | diff | comparison | revisions
dav/main.c file | annotate | diff | comparison | revisions
dav/scfg.c file | annotate | diff | comparison | revisions
dav/sync.c file | annotate | diff | comparison | revisions
dav/sync.h file | annotate | diff | comparison | revisions
--- a/dav/config.c	Mon Nov 07 19:32:17 2016 +0100
+++ b/dav/config.c	Fri Nov 11 15:03:19 2016 +0100
@@ -35,11 +35,20 @@
 #include <libxml/tree.h>
 
 #include "config.h"
+#include "main.h"
 #include <libidav/utils.h>
 
 #define xstreq(a,b) xmlStrEqual(BAD_CAST a, BAD_CAST b)
 #define xstrEQ(a,b) !xmlStrcasecmp(BAD_CAST a, BAD_CAST b)
 
+#define print_error(...) \
+    do {\
+        fprintf(stderr, "Error (config.xml): " __VA_ARGS__); \
+        fprintf(stderr, "Abort.\n"); \
+    } while(0);
+#define print_warning(...) \
+    fprintf(stderr, "Warning (config.xml): " __VA_ARGS__);
+
 #ifdef _WIN32
 #define ENV_HOME getenv("USERPROFILE")
 #else
@@ -48,8 +57,6 @@
 
 static UcxMap *repos;
 static UcxMap *keys;
-static Proxy  *http_proxy;
-static Proxy  *https_proxy;
 
 int check_config_dir(void) {
     char *file = util_concat_path(ENV_HOME, ".dav");
@@ -73,15 +80,13 @@
     xmlFreeDoc(doc);
 }
 
-void load_config(DavContext *ctx) {
+int load_config(DavContext *ctx) {
     context = ctx;
     // TODO: free the config somewhere
     repos = ucx_map_new(16);
     keys = ucx_map_new(16);
-    http_proxy = calloc(1, sizeof(Proxy));
-    https_proxy = calloc(1, sizeof(Proxy));
     if(check_config_dir()) {
-        return;
+        return 1;
     }
     
     char *file = util_concat_path(ENV_HOME, ".dav/config.xml");
@@ -97,64 +102,72 @@
                 perror("Cannot load config.xml");
             }
         }
-        return;
+        return 1;
     }
     
     xmlDoc *doc = xmlReadFile(file, NULL, 0);
     free(file);
     if(!doc) {
         fprintf(stderr, "Cannot load config.xml\n");
-        return;
+        return 1;
     }
     
     xmlNode *xml_root = xmlDocGetRootElement(doc);
     xmlNode *node = xml_root->children;
-    while(node) {
+    int ret = 0;
+    while(node && !ret) {
         if(node->type == XML_ELEMENT_NODE) {
             if(xstreq(node->name, "repository")) {
-                load_repository(node);
+                ret = load_repository(node);
             } else if(xstreq(node->name, "key")) {
-                load_key(node);
+                ret = load_key(node);
             } else if (xstreq(node->name, "http-proxy")) {
-                load_proxy(node, HTTP_PROXY);
+                ret = load_proxy(ctx->http_proxy, node, HTTP_PROXY);
             } else if (xstreq(node->name, "https-proxy")) {
-                load_proxy(node, HTTPS_PROXY);
+                ret = load_proxy(ctx->https_proxy, node, HTTPS_PROXY);
+            } else {
+                fprintf(stderr, "Unknown config element: %s\n", node->name);
+                ret = 1;
             }
         }
         node = node->next;
     }
     
     xmlFreeDoc(doc);
+    return ret;
 }
 
 void free_config(void) {
-    UcxMapIterator i = ucx_map_iterator(repos);
-    UcxKey k;
-    Repository *repo;
-    UCX_MAP_FOREACH(k, repo, i) {
-        if(repo->default_key) {
-            free(repo->default_key);
-        }
-        if(repo->name) {
-            free(repo->name);
-        }
-        if(repo->password) {
-            free(repo->password);
+    if(repos) {
+        UcxMapIterator i = ucx_map_iterator(repos);
+        UcxKey k;
+        Repository *repo;
+        UCX_MAP_FOREACH(k, repo, i) {
+            if(repo->default_key) {
+                free(repo->default_key);
+            }
+            if(repo->name) {
+                free(repo->name);
+            }
+            if(repo->password) {
+                free(repo->password);
+            }
+            if(repo->url) {
+                free(repo->url);
+            }
+            if(repo->user) {
+                free(repo->user);
+            }
+            if(repo->cert) {
+                free(repo->cert);
+            }      
+            free(repo);
         }
-        if(repo->url) {
-            free(repo->url);
-        }
-        if(repo->user) {
-            free(repo->user);
-        }
-        if(repo->cert) {
-            free(repo->cert);
-        }      
-        free(repo);
+        ucx_map_free(repos);
     }
-    ucx_map_free(repos);
-    
-    ucx_map_free(keys);
+    if(keys) {
+        ucx_map_free(keys);
+    }
 }
 
 Repository* repository_new(void) {
@@ -169,45 +182,48 @@
     return repo;
 }
 
-void load_repository(xmlNode *reponode) {
-    xmlNode *node = reponode->children;
+int load_repository(xmlNode *reponode) {
     Repository *repo = repository_new();
-    while(node) {
-        if(node->type == XML_ELEMENT_NODE) {
-            char *name = (char*)node->name;
-            char *value = util_xml_get_text(node);
-            if(value) {
-                if(repo_add_config(repo, name, value)) {
-                    fprintf(
-                            stderr,
-                            "Unkown repository config element: %s\n",
-                            name);
-                }
+    {
+        xmlNode *node = reponode->children;
+        int ret = 0;
+        while(node && !ret) {
+            if(node->type == XML_ELEMENT_NODE) {
+                char *name = (char*)node->name;
+                char *value = util_xml_get_text(node);
+                ret = repo_add_config(repo, name, value);
             }
+            node = node->next;
         }
-        node = node->next;
+        if(ret) {
+            free(repo);
+            return 1;
+        }
     }
     
     if(!repo->name) {
-        fprintf(
-                stderr,
-                "Cannot load config.xml: missing name for repository.\n");
-        fprintf(stderr, "Abort.\n");
-        exit(-1);
+        print_error("missing name for repository.\n");
+        return 1;
     }
     if(!repo->url) {
-        fprintf(
-                stderr,
-                "Cannot load config.xml: "
-                "missing url for repository '%s'.\n", repo->name);
-        fprintf(stderr, "Abort.\n");
-        exit(-1);
+        print_error("missing url for repository '%s'.\n", repo->name);
+        return 1;
     }
     
     ucx_map_cstr_put(repos, repo->name, repo);
+    return 0;
 }
 
-int repo_add_config(Repository *repo, char *key, char *value) {  
+int repo_add_config(Repository *repo, char *key, char *value) {
+    /* every key needs a value */
+    if(!value) {
+        /* TODO: maybe this should only be reported, if the key is valid
+         * But this makes the code very ugly.
+         */
+        print_error("missing value for config element: %s\n", key);
+        return 1;
+    }
+    
     if(xstreq(key, "name")) {
         repo->name = strdup(value);
     } else if(xstreq(key, "url")) {
@@ -263,7 +279,7 @@
 #endif
 #endif
         else {
-            fprintf(stderr, "Unknown ssl version: %s\n", value);
+            print_warning("unknown ssl version: %s\n", value);
         }
     } else if(xstreq(key, "authmethods")) {
         repo->authmethods = CURLAUTH_NONE;
@@ -284,56 +300,76 @@
             } else if(xstrEQ(value, "none")) {
                 /* skip */
             } else {
-                fprintf(stderr, "Unknown authentication method: %s\n", value);
+                print_warning("unknown authentication method: %s\n", value);
             }
             meth = strtok(NULL, delims);
         }
         free(meths);
     } else {
-        return -1;
+        print_error("unkown repository config element: %s\n", key);
+        return 1;
     }
     return 0;
 }
 
-void load_proxy(xmlNode *proxynode, int type) {
-    Proxy *proxy;
+int load_proxy(DavProxy *proxy, xmlNode *proxynode, int type) {
     const char *stype;
-    if (type == HTTPS_PROXY) {
-        proxy = https_proxy;
+    if(type == HTTPS_PROXY) {
         stype = "https";
-    } else if (type == HTTP_PROXY) {
-        proxy = http_proxy;
+    } else if(type == HTTP_PROXY) {
         stype = "http";
     }
     
+    if(!proxy) {
+        print_error("no memory reserved for %s proxy.\n", stype);
+        return 1;
+    }
+    
     xmlNode *node = proxynode->children;
-    while(node) {
+    int ret = 0;
+    while(node && !ret) {
         if(node->type == XML_ELEMENT_NODE) {
             char *value = util_xml_get_text(node);
-            if(!value) {
-                // next
-            } else if(xstreq(node->name, "url")) {
-                proxy->url = strdup(value);
+            int reportmissingvalue = 0;
+            if(xstreq(node->name, "url")) {
+                if(!(reportmissingvalue = !value)) {
+                    proxy->url = strdup(value);
+                }
             } else if(xstreq(node->name, "user")) {
-                proxy->user = strdup(value);
+                if(!(reportmissingvalue = !value)) {
+                    proxy->username = strdup(value);
+                }
             } else if(xstreq(node->name, "password")) {
-                proxy->password = util_base64decode(value);
+                if(!(reportmissingvalue = !value)) {
+                    proxy->password = util_base64decode(value);
+                }
             } else if(xstreq(node->name, "no")) {
-                proxy->no = strdup(value);
+                if(!(reportmissingvalue = !value)) {
+                    proxy->no_proxy = strdup(value);
+                }
+            } else {
+                print_error("invalid element for proxy config: %s\n",
+                        node->name);
+                ret = 1;
+            }
+            if (reportmissingvalue) {
+                print_error("missing value for proxy configuration "
+                        "element '%s'.\n", node->name);
+                ret = 1;
             }
         }
         node = node->next;
     }
     
-    if(!proxy->url) {
-        fprintf(stderr,
-            "Cannot load config.xml: missing url for %s proxy.\n", stype);
-        fprintf(stderr, "Abort.\n");
-        exit(-1);
+    if(!ret && !proxy->url) {
+        print_error("missing url for %s proxy.\n", stype);
+        return 1;
     }
+    
+    return ret;
 }
 
-void load_key(xmlNode *keynode) {
+int load_key(xmlNode *keynode) {
     xmlNode *node = keynode->children;
     Key *key = calloc(1, sizeof(Key));
     key->type = KEY_AES256;
@@ -353,7 +389,7 @@
                     key->data = key_data.ptr;
                     key->length = key_data.length;
                 } else {
-                    fprintf(stderr, "Error: Cannot key from file: %s\n", value);
+                    print_error("cannot get key from file: %s\n", value);
                     error = 1;
                 }
             } else if(xstreq(node->name, "type")) {
@@ -362,7 +398,7 @@
                 } else if(!strcmp(value, "aes256")) {
                     key->type = KEY_AES256;
                 } else {
-                    fprintf(stderr, "Error: unknown key type %s\n", value);
+                    print_error("unknown key type %s\n", value);
                     error = 1;
                 }
             }
@@ -373,27 +409,19 @@
     
     if(!error && key->name) {
         error = 0;
+        size_t expected_length = 0;
         if(key->type == KEY_AES128) {
-            if(key->length < 16) {
-                fprintf(
-                        stderr,
-                        "Error: Key %s is too small (%zu < 16)\n",
-                        key->name,
-                        key->length);
-                error = 1;
-            }
-            key->length = 16;
+            expected_length = 16;
         }
         if(key->type == KEY_AES256) {
-            if(key->length < 32) {
-                fprintf(
-                        stderr,
-                        "Error: Key %s is too small (%zu < 32)\n",
-                        key->name,
-                        key->length);
-                error = 1;
-            }
-            key->length = 32;
+            expected_length = 32;
+        }
+        if(key->length < expected_length) {
+            print_error("key %s is too small (%zu < %zu)\n",
+                    key->name,
+                    key->length,
+                    expected_length);
+            error = 1;
         }
         
         // add key to context
@@ -409,6 +437,9 @@
             free(key->data);
         }
         free(key);
+        return 1;
+    } else {
+        return 0;
     }
 }
 
@@ -473,15 +504,6 @@
     return ucx_map_cstr_get(keys, name);
 }
 
-Proxy* get_http_proxy(void) {
-    return http_proxy;
-}
-
-Proxy* get_https_proxy(void) {
-    return https_proxy;
-}
-
-
 int add_repository(Repository *repo) {
     char *file = util_concat_path(ENV_HOME, ".dav/config.xml");
     xmlDoc *doc = xmlReadFile(file, NULL, 0);
--- a/dav/config.h	Mon Nov 07 19:32:17 2016 +0100
+++ b/dav/config.h	Fri Nov 11 15:03:19 2016 +0100
@@ -66,19 +66,12 @@
     int ssl_version;
     unsigned long authmethods;
 };
-
-struct Proxy {
-    char *url;
-    char *user;
-    char *password;
-    char *no;
-};
     
-void load_config(DavContext *ctx);
+int load_config(DavContext *ctx);
 void free_config(void);
-void load_repository(xmlNode *reponode);
-void load_key(xmlNode *keynode);
-void load_proxy(xmlNode *proxynode, int type);
+int load_repository(xmlNode *reponode);
+int load_key(xmlNode *keynode);
+int load_proxy(DavProxy*, xmlNode *proxynode, int type);
 sstr_t load_key_file(char *filename);
 
 Repository* repository_new(void);
@@ -88,8 +81,6 @@
 int get_repository_flags(Repository *repo);
 DavSession *repository_session(Repository *repo);
 Key* get_key(char *name);
-Proxy* get_http_proxy(void);
-Proxy* get_https_proxy(void);
 
 int add_repository(Repository *repo);
 int list_repositories(void);
--- a/dav/main.c	Mon Nov 07 19:32:17 2016 +0100
+++ b/dav/main.c	Fri Nov 11 15:03:19 2016 +0100
@@ -66,20 +66,6 @@
 }
 
 int main(int argc, char **argv) {
-    xmlGenericErrorFunc fnc = xmlerrorfnc;
-    initGenericErrorDefaultFunc(&fnc);
-    ctx = dav_context_new();
-    dav_add_namespace(ctx, "apache", "http://apache.org/dav/props/");
-    load_config(ctx);
-    printxmlerror = 0;
-#ifdef DO_THE_TEST
-    test();
-    return 0;
-#endif
-    
-    memcpy(ctx->http_proxy, get_http_proxy(), sizeof(Proxy));
-    memcpy(ctx->https_proxy, get_https_proxy(), sizeof(Proxy));
-    
     if(argc < 2) {
         fprintf(stderr, "Missing command\n");
         print_usage(argv[0]);
@@ -94,46 +80,66 @@
         return -1;
     }
     
-    
-    int ret = -1;
-    if(!strcasecmp(cmd, "list") || !strcasecmp(cmd, "ls")) {
-        ret = cmd_list(args);
-    } else if(!strcasecmp(cmd, "get")) {
-        ret = cmd_get(args);
-    } else if(!strcasecmp(cmd, "put")) {
-        ret = cmd_put(args);
-    } else if(
-            !strcasecmp(cmd, "remove") ||
-            !strcasecmp(cmd, "rm") ||
-            !strcasecmp(cmd, "delete"))
-    {
-        ret = cmd_remove(args);
-    } else if(!strcasecmp(cmd, "mkdir") || !strcasecmp(cmd, "mkcol")) {
-        ret = cmd_mkdir(args);
-    } else if(!strcasecmp(cmd, "copy") || !strcasecmp(cmd, "cp")) {
-        ret = cmd_move(args, true);
-    } else if(!strcasecmp(cmd, "move") || !strcasecmp(cmd, "mv")) {
-        ret = cmd_move(args, false);
-    } else if(!strcasecmp(cmd, "date")) {
-        ret = cmd_date(args);
-    } else if(!strcasecmp(cmd, "set-property")) {
-        ret = cmd_set_property(args);
-    } else if(!strcasecmp(cmd, "get-property")) {
-        ret = cmd_get_property(args);
-    } else if(!strcasecmp(cmd, "lock")) {
-        ret = cmd_lock(args);
-    } else if(!strcasecmp(cmd, "unlock")) {
-        ret = cmd_unlock(args);
-    }  else if(!strcasecmp(cmd, "info")) {
-        ret = cmd_info(args);
-    } else if(!strcasecmp(cmd, "add-repository")) {
-        ret = cmd_add_repository(args);
-    } else if(!strcasecmp(cmd, "list-repositories")) {
-        ret = list_repositories();
-    } else if(!strcasecmp(cmd, "version") || !strcasecmp(cmd, "-version") || !strcasecmp(cmd, "--version")) {
-        fprintf(stderr, "dav %s\n", DAV_VERSION);
-    } else {
-        print_usage(argv[0]);
+    xmlGenericErrorFunc fnc = xmlerrorfnc;
+    initGenericErrorDefaultFunc(&fnc);
+    ctx = dav_context_new();
+    dav_add_namespace(ctx, "apache", "http://apache.org/dav/props/");
+    int cfgret = load_config(ctx);
+    int ret = EXIT_FAILURE;
+    printxmlerror = 0;
+#ifdef DO_THE_TEST
+    test();
+    return 0;
+#endif
+    if(!strcmp(cmd, "check") || !strcmp(cmd, "check-config")) {
+        if(!cfgret) {
+            fprintf(stdout, "Configuration OK.\n");
+            ret = EXIT_SUCCESS;
+        } else {
+            /* no output, the warnings are written by load_config */
+            ret = EXIT_FAILURE;
+        }
+    } else if(!cfgret) {
+        if(!strcasecmp(cmd, "list") || !strcasecmp(cmd, "ls")) {
+            ret = cmd_list(args);
+        } else if(!strcasecmp(cmd, "get")) {
+            ret = cmd_get(args);
+        } else if(!strcasecmp(cmd, "put")) {
+            ret = cmd_put(args);
+        } else if(
+                !strcasecmp(cmd, "remove") ||
+                !strcasecmp(cmd, "rm") ||
+                !strcasecmp(cmd, "delete"))
+        {
+            ret = cmd_remove(args);
+        } else if(!strcasecmp(cmd, "mkdir") || !strcasecmp(cmd, "mkcol")) {
+            ret = cmd_mkdir(args);
+        } else if(!strcasecmp(cmd, "copy") || !strcasecmp(cmd, "cp")) {
+            ret = cmd_move(args, true);
+        } else if(!strcasecmp(cmd, "move") || !strcasecmp(cmd, "mv")) {
+            ret = cmd_move(args, false);
+        } else if(!strcasecmp(cmd, "date")) {
+            ret = cmd_date(args);
+        } else if(!strcasecmp(cmd, "set-property")) {
+            ret = cmd_set_property(args);
+        } else if(!strcasecmp(cmd, "get-property")) {
+            ret = cmd_get_property(args);
+        } else if(!strcasecmp(cmd, "lock")) {
+            ret = cmd_lock(args);
+        } else if(!strcasecmp(cmd, "unlock")) {
+            ret = cmd_unlock(args);
+        }  else if(!strcasecmp(cmd, "info")) {
+            ret = cmd_info(args);
+        } else if(!strcasecmp(cmd, "add-repository")) {
+            ret = cmd_add_repository(args);
+        } else if(!strcasecmp(cmd, "list-repositories")) {
+            ret = list_repositories();
+        } else if(!strcasecmp(cmd, "version") || !strcasecmp(cmd, "-version")
+                || !strcasecmp(cmd, "--version")) {
+            fprintf(stderr, "dav %s\n", DAV_VERSION);
+        } else {
+            print_usage(argv[0]);
+        }
     }
     
     dav_context_destroy(ctx);
@@ -195,6 +201,7 @@
     fprintf(stderr, "Config commands:\n");
     fprintf(stderr, "        add-repository\n");
     fprintf(stderr, "        list-repositories\n");
+    fprintf(stderr, "        check (or check-config)\n");
     fprintf(stderr, "\n");
     fprintf(stderr,
             "Instead of an url you can pass a repository name "
--- a/dav/scfg.c	Mon Nov 07 19:32:17 2016 +0100
+++ b/dav/scfg.c	Fri Nov 11 15:03:19 2016 +0100
@@ -38,6 +38,15 @@
 
 #define xstreq(a,b) xmlStrEqual(BAD_CAST a, BAD_CAST b)
 
+
+#define print_error(...) \
+    do {\
+        fprintf(stderr, "Error (sync.xml): " __VA_ARGS__); \
+        fprintf(stderr, "Abort.\n"); \
+    } while(0);
+#define print_warning(...) \
+    fprintf(stderr, "Warning (sync.xml): " __VA_ARGS__);
+
 #ifdef _WIN32
 #define ENV_HOME getenv("USERPROFILE")
 #else
@@ -71,7 +80,8 @@
         switch(errno) {
             case ENOENT: {
                 if(create_default_sync_config(file)) {
-                    return -1;
+                    /* this recursion is safe: ENOENT cannot occur again */
+                    return load_sync_config();
                 }
                 break;
             }
@@ -85,21 +95,20 @@
     
     xmlDoc *doc = xmlReadFile(file, NULL, 0);
     if(!doc) {
-        fprintf(stderr, "Broken configuration file\n");
+        fprintf(stderr, "Cannot load sync.xml\n");
         free(file);
         return -1;
     }
     
     int ret = 0;
     xmlNode *node = xmlDocGetRootElement(doc)->children;
-    while(node) {
+    while(node && !ret) {
         if(node->type == XML_ELEMENT_NODE) {
             if(xstreq(node->name, "directory")) {
-                if(scfg_load_directory(node)) {
-                    ret = 1;
-                    ucx_map_free(directories);
-                    break;
-                }
+                ret = scfg_load_directory(node);
+            } else {
+                print_error("unknown config element: %s\n", node->name);
+                ret = 1;
             }
         }
         node = node->next;
@@ -126,12 +135,21 @@
     while(node) {
         if(node->type == XML_ELEMENT_NODE) {
             char *value = util_xml_get_text(node);
-            if(!value) {
+            if(xstreq(node->name, "include")) {
+                if(value) {
+                    *include = add_regex_pattern(*include, value);
+                }
+            } else if(xstreq(node->name, "exclude")) {
+                if(value) {
+                    *exclude = add_regex_pattern(*exclude, value);
+                }
+            } else {
+                print_error("unknown filter config element: %s\n", node->name);
                 return 1;
-            } else if(xstreq(node->name, "include")) {
-                *include = add_regex_pattern(*include, value);
-            } else if(xstreq(node->name, "exclude")) {
-                *exclude = add_regex_pattern(*exclude, value);
+            }
+            if(!value) {
+                print_error("missing value for filter: %s\n", node->name);
+                return 1;
             }
         }
         
@@ -159,9 +177,16 @@
     while(node) {
         if(node->type == XML_ELEMENT_NODE) {
             char *value = util_xml_get_text(node);
+            /* every key needs a value */
             if(!value) {
-                // next
-            } else if(xstreq(node->name, "name")) {
+                /* TODO: maybe this should only be reported, if the key is valid
+                 * But this makes the code very ugly.
+                 */
+                print_error("missing value for directory element: %s\n",
+                        node->name);
+                return 1;
+            }
+            if(xstreq(node->name, "name")) {
                 name = value;
             } else if(xstreq(node->name, "path")) {
                 path = value;
@@ -173,7 +198,7 @@
                 repository = value;
             } else if(xstreq(node->name, "filter")) {
                 if(scfg_load_filter(node, &include, &exclude)) {
-                    return -1;
+                    return 1;
                 }
             } else if(xstreq(node->name, "database")) {
                 database = value;
@@ -182,8 +207,8 @@
                 if(util_strtoint(value, &i) && i >= 0) {
                     max_retry = (int)i;
                 } else {
-                    fprintf(stderr, "Warning: sync.xml: unsigned integer value "
-                                    "expected in <max-retry> element\n");
+                    print_warning("unsigned integer value "
+                            "expected in <max-retry> element\n");
                 }
             } else if(xstreq(node->name, "backup-on-pull")) {
                 backuppull = util_getboolean(value);
@@ -191,26 +216,30 @@
                 lockpull = util_getboolean(value);
             } else if(xstreq(node->name, "lock-push")) {
                 lockpush = util_getboolean(value);
+            } else {
+                print_error("unknown directory config element: %s\n",
+                        node->name);
+                return 1;
             }
         }
         node = node->next;
     }
     
     if(!name) {
-        fprintf(stderr, "Missing name element for directory\n");
-        return -1;
+        print_error("missing name element for directory\n");
+        return 1;
     }
     if(!path) {
-        fprintf(stderr, "Missing path element for directory\n");
-        return -1;
+        print_error("missing path element for directory %s\n", name);
+        return 1;
     }
     if(!repository) {
-        fprintf(stderr, "Missing repository element for directory\n");
-        return -1;
+        print_error("missing repository element for directory %s\n", name);
+        return 1;
     }
     if(!database) {
-        fprintf(stderr, "Missing database element for directory\n");
-        return -1;
+        print_error("missing database element for directory %s\n", name);
+        return 1;
     }
     
     SyncDirectory *dir = malloc(sizeof(SyncDirectory));
@@ -426,34 +455,36 @@
 
 
 void free_sync_config() {
-    UcxMapIterator i = ucx_map_iterator(directories);
-    SyncDirectory *dir;
-    UCX_MAP_FOREACH(elm, dir, i) {
-        free(dir->name);
-        free(dir->path);
-        free(dir->repository);
-        free(dir->database);
-        
-        if(dir->collection) {
-            free(dir->collection);
-        }
-        if(dir->trash) {
-            free(dir->trash);
+    if(directories) {
+        UcxMapIterator i = ucx_map_iterator(directories);
+        SyncDirectory *dir;
+        UCX_MAP_FOREACH(elm, dir, i) {
+            free(dir->name);
+            free(dir->path);
+            free(dir->repository);
+            free(dir->database);
+
+            if(dir->collection) {
+                free(dir->collection);
+            }
+            if(dir->trash) {
+                free(dir->trash);
+            }
+
+            UCX_FOREACH(elm, dir->include) {
+                regfree(elm->data);
+                free(elm->data);
+            }
+            ucx_list_free(dir->include);
+            UCX_FOREACH(elm, dir->exclude) {
+                regfree(elm->data);
+                free(elm->data);
+            }
+            ucx_list_free(dir->exclude);
+
+            free(dir);
         }
-        
-        UCX_FOREACH(elm, dir->include) {
-            regfree(elm->data);
-            free(elm->data);
-        }
-        ucx_list_free(dir->include);
-        UCX_FOREACH(elm, dir->exclude) {
-            regfree(elm->data);
-            free(elm->data);
-        }
-        ucx_list_free(dir->exclude);
-        
-        free(dir);
+
+        ucx_map_free(directories);
     }
-    
-    ucx_map_free(directories);
 }
--- a/dav/sync.c	Mon Nov 07 19:32:17 2016 +0100
+++ b/dav/sync.c	Fri Nov 11 15:03:19 2016 +0100
@@ -73,49 +73,48 @@
     }
     int ret = EXIT_FAILURE;
     
-    int loadcfg = 1;
-    if(!strcasecmp(cmd, "version") || !strcasecmp(cmd, "-version") || !strcasecmp(cmd, "--version")) {
+    if(!strcasecmp(cmd, "version") || !strcasecmp(cmd, "-version")
+            || !strcasecmp(cmd, "--version")) {
         fprintf(stderr, "dav-sync %s\n", DAV_VERSION);
-        loadcfg = 0;
         cmd_args_free(args);
         return -1;
     }
     
-    if(loadcfg) {
-        xmlGenericErrorFunc fnc = xmlerrorfnc;
-        initGenericErrorDefaultFunc(&fnc);
-        ctx = dav_context_new();
-        load_config(ctx);
-
-        // copy proxy config
-        memcpy(ctx->http_proxy, get_http_proxy(), sizeof(Proxy));
-        memcpy(ctx->https_proxy, get_https_proxy(), sizeof(Proxy));
-        
-        if(load_sync_config()) {
-            cmd_args_free(args);
-            dav_context_destroy(ctx);
-            return EXIT_FAILURE;
-        }
-    }
+    xmlGenericErrorFunc fnc = xmlerrorfnc;
+    initGenericErrorDefaultFunc(&fnc);
+    ctx = dav_context_new();
+    int cfgret = load_config(ctx) || load_sync_config();
     
-    if(!strcmp(cmd, "pull")) {
-        ret = cmd_pull(args);
-    } else if(!strcmp(cmd, "push")) {
-        ret = cmd_push(args);
-    } else if(!strcmp(cmd, "resolve-conflicts")) {
-        ret = cmd_resolve_conflicts(args);
-    } else if(!strcmp(cmd, "delete-conflicts")) {
-        ret = cmd_delete_conflicts(args);
-    } else if(!strcmp(cmd, "trash-info")) {
-        ret = cmd_trash_info(args);
-    } else if(!strcmp(cmd, "empty-trash")) {
-        ret = cmd_empty_trash(args);
-    } else if(!strcmp(cmd, "add-directory")) {
-        ret = cmd_add_directory(args);
-    } else if(!strcmp(cmd, "list-directories")) {
-        ret = list_syncdirs();
-    } else {
-        print_usage(argv[0]);
+    if(!strcmp(cmd, "check") || !strcmp(cmd, "check-config")) {
+        if(!cfgret) {
+            fprintf(stdout, "Configuration OK.\n");
+            ret = EXIT_SUCCESS;
+        } else {
+            /* no output, the warnings are written by load_config */
+            ret = EXIT_FAILURE;
+        }
+    } else if(!cfgret) {
+        if(!strcmp(cmd, "pull")) {
+            ret = cmd_pull(args);
+        } else if(!strcmp(cmd, "push")) {
+            ret = cmd_push(args);
+        } else if(!strcmp(cmd, "resolve-conflicts")) {
+            ret = cmd_resolve_conflicts(args);
+        } else if(!strcmp(cmd, "delete-conflicts")) {
+            ret = cmd_delete_conflicts(args);
+        } else if(!strcmp(cmd, "trash-info")) {
+            ret = cmd_trash_info(args);
+        } else if(!strcmp(cmd, "empty-trash")) {
+            ret = cmd_empty_trash(args);
+        } else if(!strcmp(cmd, "add-directory")) {
+            ret = cmd_add_directory(args);
+        } else if(!strcmp(cmd, "list-directories")) {
+            ret = list_syncdirs();
+        } else if(!strcmp(cmd, "check-repositories")) {
+            ret = cmd_check_repositories();
+        } else {
+            print_usage(argv[0]);
+        }
     }
     
     // cleanup
@@ -151,7 +150,9 @@
     
     fprintf(stderr, "Config commands:\n");
     fprintf(stderr, "        add-directory\n");
-    fprintf(stderr, "        list-directories\n\n");
+    fprintf(stderr, "        list-directories\n");
+    fprintf(stderr, "        check (or check-config)\n");
+    fprintf(stderr, "        check-repositories\n\n");
 }
 
 static int res_matches_filter(SyncDirectory *dir, char *res_path) {
@@ -1633,3 +1634,8 @@
     
     return ret;
 }
+
+int cmd_check_repositories() {
+    fprintf(stderr, "Not implemented.\n");
+    return EXIT_FAILURE;
+}
--- a/dav/sync.h	Mon Nov 07 19:32:17 2016 +0100
+++ b/dav/sync.h	Fri Nov 11 15:03:19 2016 +0100
@@ -88,6 +88,8 @@
 int cmd_empty_trash(CmdArgs *args);
 int cmd_add_directory(CmdArgs *args);
 
+int cmd_check_repositories();
+
 #ifdef	__cplusplus
 }
 #endif

mercurial