LCOV - code coverage report
Current view: top level - auditor - taler-auditor-sync.c (source / functions) Hit Total Coverage
Test: GNU Taler exchange coverage report Lines: 127 196 64.8 %
Date: 2021-08-30 06:43:37 Functions: 11 11 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2020 Taler Systems SA
       4             : 
       5             :   TALER is free software; you can redistribute it and/or modify it under the
       6             :   terms of the GNU General Public License as published by the Free Software
       7             :   Foundation; either version 3, or (at your option) any later version.
       8             : 
       9             :   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
      10             :   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
      11             :   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
      12             : 
      13             :   You should have received a copy of the GNU General Public License along with
      14             :   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
      15             : */
      16             : /**
      17             :  * @file taler-auditor-sync.c
      18             :  * @brief Tool used by the auditor to make a 'safe' copy of the exchanges' database.
      19             :  * @author Christian Grothoff
      20             :  */
      21             : #include <platform.h>
      22             : #include "taler_exchangedb_lib.h"
      23             : 
      24             : 
      25             : /**
      26             :  * Handle to access the exchange's source database.
      27             :  */
      28             : static struct TALER_EXCHANGEDB_Plugin *src;
      29             : 
      30             : /**
      31             :  * Handle to access the exchange's destination database.
      32             :  */
      33             : static struct TALER_EXCHANGEDB_Plugin *dst;
      34             : 
      35             : /**
      36             :  * Return value from #main().
      37             :  */
      38             : static int global_ret;
      39             : 
      40             : /**
      41             :  * Main task to do synchronization.
      42             :  */
      43             : static struct GNUNET_SCHEDULER_Task *sync_task;
      44             : 
      45             : /**
      46             :  * What is our target transaction size (number of records)?
      47             :  */
      48             : static unsigned int transaction_size = 512;
      49             : 
      50             : /**
      51             :  * Number of records copied in this transaction.
      52             :  */
      53             : static unsigned long long actual_size;
      54             : 
      55             : /**
      56             :  * Terminate once synchronization is achieved.
      57             :  */
      58             : static int exit_if_synced;
      59             : 
      60             : 
      61             : /**
      62             :  * Information we track per replicated table.
      63             :  */
      64             : struct Table
      65             : {
      66             :   /**
      67             :    * Which table is this record about?
      68             :    */
      69             :   enum TALER_EXCHANGEDB_ReplicatedTable rt;
      70             : 
      71             :   /**
      72             :    * Up to which record is the destination table synchronized.
      73             :    */
      74             :   uint64_t start_serial;
      75             : 
      76             :   /**
      77             :    * Highest serial in the source table.
      78             :    */
      79             :   uint64_t end_serial;
      80             : 
      81             :   /**
      82             :    * Marker for the end of the list of #tables.
      83             :    */
      84             :   bool end;
      85             : };
      86             : 
      87             : 
      88             : /**
      89             :  * Information about replicated tables.
      90             :  */
      91             : static struct Table tables[] = {
      92             :   { .rt = TALER_EXCHANGEDB_RT_DENOMINATIONS},
      93             :   { .rt = TALER_EXCHANGEDB_RT_DENOMINATION_REVOCATIONS},
      94             :   { .rt = TALER_EXCHANGEDB_RT_RESERVES},
      95             :   { .rt = TALER_EXCHANGEDB_RT_RESERVES_IN},
      96             :   { .rt = TALER_EXCHANGEDB_RT_RESERVES_CLOSE},
      97             :   { .rt = TALER_EXCHANGEDB_RT_RESERVES_OUT},
      98             :   { .rt = TALER_EXCHANGEDB_RT_AUDITORS},
      99             :   { .rt = TALER_EXCHANGEDB_RT_AUDITOR_DENOM_SIGS},
     100             :   { .rt = TALER_EXCHANGEDB_RT_EXCHANGE_SIGN_KEYS},
     101             :   { .rt = TALER_EXCHANGEDB_RT_SIGNKEY_REVOCATIONS},
     102             :   { .rt = TALER_EXCHANGEDB_RT_KNOWN_COINS},
     103             :   { .rt = TALER_EXCHANGEDB_RT_REFRESH_COMMITMENTS},
     104             :   { .rt = TALER_EXCHANGEDB_RT_REFRESH_REVEALED_COINS},
     105             :   { .rt = TALER_EXCHANGEDB_RT_REFRESH_TRANSFER_KEYS},
     106             :   { .rt = TALER_EXCHANGEDB_RT_DEPOSITS},
     107             :   { .rt = TALER_EXCHANGEDB_RT_REFUNDS},
     108             :   { .rt = TALER_EXCHANGEDB_RT_WIRE_OUT},
     109             :   { .rt = TALER_EXCHANGEDB_RT_AGGREGATION_TRACKING},
     110             :   { .rt = TALER_EXCHANGEDB_RT_WIRE_FEE},
     111             :   { .rt = TALER_EXCHANGEDB_RT_RECOUP},
     112             :   { .rt = TALER_EXCHANGEDB_RT_RECOUP_REFRESH },
     113             :   { .end = true }
     114             : };
     115             : 
     116             : 
     117             : /**
     118             :  * Closure for #do_insert.
     119             :  */
     120             : struct InsertContext
     121             : {
     122             :   /**
     123             :    * Table we are replicating.
     124             :    */
     125             :   struct Table *table;
     126             : 
     127             :   /**
     128             :    * Set to error if insertion created an error.
     129             :    */
     130             :   enum GNUNET_DB_QueryStatus qs;
     131             : };
     132             : 
     133             : 
     134             : /**
     135             :  * Function called on data to replicate in the auditor's database.
     136             :  *
     137             :  * @param cls closure, a `struct InsertContext`
     138             :  * @param td record from an exchange table
     139             :  * @return #GNUNET_OK to continue to iterate,
     140             :  *         #GNUNET_SYSERR to fail with an error
     141             :  */
     142             : static int
     143         948 : do_insert (void *cls,
     144             :            const struct TALER_EXCHANGEDB_TableData *td)
     145             : {
     146         948 :   struct InsertContext *ctx = cls;
     147             :   enum GNUNET_DB_QueryStatus qs;
     148             : 
     149         948 :   if (0 >= ctx->qs)
     150           0 :     return GNUNET_SYSERR;
     151         948 :   qs = dst->insert_records_by_table (dst->cls,
     152             :                                      td);
     153         948 :   if (0 >= qs)
     154             :   {
     155           0 :     switch (qs)
     156             :     {
     157           0 :     case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
     158           0 :       GNUNET_assert (0);
     159             :       break;
     160           0 :     case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
     161           0 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     162             :                   "Failed to insert record into table %d: no change\n",
     163             :                   td->table);
     164           0 :       break;
     165           0 :     case GNUNET_DB_STATUS_SOFT_ERROR:
     166           0 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     167             :                   "Serialization error inserting record into table %d (will retry)\n",
     168             :                   td->table);
     169           0 :       break;
     170           0 :     case GNUNET_DB_STATUS_HARD_ERROR:
     171           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     172             :                   "Failed to insert record into table %d: hard error\n",
     173             :                   td->table);
     174           0 :       break;
     175             :     }
     176           0 :     ctx->qs = qs;
     177           0 :     return GNUNET_SYSERR;
     178             :   }
     179         948 :   actual_size++;
     180         948 :   ctx->table->start_serial = td->serial;
     181         948 :   return GNUNET_OK;
     182             : }
     183             : 
     184             : 
     185             : /**
     186             :  * Run one replication transaction.
     187             :  *
     188             :  * @return #GNUNET_OK on success, #GNUNET_SYSERR to rollback
     189             :  */
     190             : static enum GNUNET_GenericReturnValue
     191           2 : transact (void)
     192             : {
     193           2 :   struct InsertContext ctx = {
     194             :     .qs = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT
     195             :   };
     196             : 
     197           2 :   if (0 >
     198           2 :       src->start (src->cls,
     199             :                   "lookup src serials"))
     200           0 :     return GNUNET_SYSERR;
     201          44 :   for (unsigned int i = 0; ! tables[i].end; i++)
     202          42 :     src->lookup_serial_by_table (src->cls,
     203             :                                  tables[i].rt,
     204             :                                  &tables[i].end_serial);
     205           2 :   if (0 >
     206           2 :       src->commit (src->cls))
     207           0 :     return GNUNET_SYSERR;
     208           2 :   if (GNUNET_OK !=
     209           2 :       dst->start (src->cls,
     210             :                   "lookup dst serials"))
     211           0 :     return GNUNET_SYSERR;
     212          44 :   for (unsigned int i = 0; ! tables[i].end; i++)
     213          42 :     dst->lookup_serial_by_table (dst->cls,
     214             :                                  tables[i].rt,
     215             :                                  &tables[i].start_serial);
     216           2 :   if (0 >
     217           2 :       dst->commit (dst->cls))
     218           0 :     return GNUNET_SYSERR;
     219          44 :   for (unsigned int i = 0; ! tables[i].end; i++)
     220             :   {
     221          42 :     struct Table *table = &tables[i];
     222             : 
     223          42 :     if (table->start_serial == table->end_serial)
     224          28 :       continue;
     225          14 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     226             :                 "Replicating table %d from %llu to %llu\n",
     227             :                 i,
     228             :                 (unsigned long long) table->start_serial,
     229             :                 (unsigned long long) table->end_serial);
     230          14 :     ctx.table = table;
     231          28 :     while (table->start_serial < table->end_serial)
     232             :     {
     233             :       enum GNUNET_DB_QueryStatus qs;
     234             : 
     235          14 :       if (GNUNET_OK !=
     236          14 :           src->start (src->cls,
     237             :                       "copy table (src)"))
     238           0 :         return GNUNET_SYSERR;
     239          14 :       if (GNUNET_OK !=
     240          14 :           dst->start (dst->cls,
     241             :                       "copy table (dst)"))
     242           0 :         return GNUNET_SYSERR;
     243          14 :       qs = src->lookup_records_by_table (src->cls,
     244             :                                          table->rt,
     245             :                                          table->start_serial,
     246             :                                          &do_insert,
     247             :                                          &ctx);
     248          14 :       if (ctx.qs < 0)
     249           0 :         qs = ctx.qs;
     250          14 :       if (GNUNET_DB_STATUS_HARD_ERROR == qs)
     251             :       {
     252           0 :         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     253             :                     "Failed to lookup records from table %d: hard error\n",
     254             :                     i);
     255           0 :         global_ret = EXIT_FAILURE;
     256           0 :         return GNUNET_SYSERR;
     257             :       }
     258          14 :       if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
     259             :       {
     260           0 :         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     261             :                     "Serialization error looking up records from table %d (will retry)\n",
     262             :                     i);
     263           0 :         return GNUNET_SYSERR; /* will retry */
     264             :       }
     265          14 :       if (0 == qs)
     266             :       {
     267           0 :         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     268             :                     "Failed to lookup records from table %d: no results\n",
     269             :                     i);
     270           0 :         GNUNET_break (0); /* should be impossible */
     271           0 :         global_ret = EXIT_FAILURE;
     272           0 :         return GNUNET_SYSERR;
     273             :       }
     274          14 :       if (0 == ctx.qs)
     275           0 :         return GNUNET_SYSERR; /* insertion failed, maybe record existed? try again */
     276          14 :       src->rollback (src->cls);
     277          14 :       qs = dst->commit (dst->cls);
     278          14 :       if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
     279             :       {
     280           0 :         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     281             :                     "Serialization error committing transaction on table %d (will retry)\n",
     282             :                     i);
     283           0 :         continue;
     284             :       }
     285          14 :       if (GNUNET_DB_STATUS_HARD_ERROR == qs)
     286             :       {
     287           0 :         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     288             :                     "Hard error committing transaction on table %d\n",
     289             :                     i);
     290           0 :         global_ret = EXIT_FAILURE;
     291           0 :         return GNUNET_SYSERR;
     292             :       }
     293             :     }
     294             :   }
     295             :   /* we do not care about conflicting UPDATEs to src table, so safe to just rollback */
     296           2 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     297             :               "Sync pass completed successfully with %llu updates\n",
     298             :               actual_size);
     299           2 :   return GNUNET_OK;
     300             : }
     301             : 
     302             : 
     303             : /**
     304             :  * Task to do the actual synchronization work.
     305             :  *
     306             :  * @param cls NULL, unused
     307             :  */
     308             : static void
     309           2 : do_sync (void *cls)
     310             : {
     311             :   static struct GNUNET_TIME_Relative delay;
     312             : 
     313           2 :   sync_task = NULL;
     314           2 :   actual_size = 0;
     315           2 :   if (GNUNET_SYSERR ==
     316           2 :       src->preflight (src->cls))
     317             :   {
     318           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     319             :                 "Failed to begin transaction with data source. Exiting\n");
     320           0 :     return;
     321             :   }
     322           2 :   if (GNUNET_SYSERR ==
     323           2 :       dst->preflight (dst->cls))
     324             :   {
     325           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     326             :                 "Failed to begin transaction with data destination. Exiting\n");
     327           0 :     return;
     328             :   }
     329           2 :   if (GNUNET_OK != transact ())
     330             :   {
     331           0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     332             :                 "Transaction failed, rolling back\n");
     333           0 :     src->rollback (src->cls);
     334           0 :     dst->rollback (dst->cls);
     335             :   }
     336           2 :   if (0 != global_ret)
     337             :   {
     338           0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     339             :                 "Transaction failed permanently, exiting\n");
     340           0 :     return;
     341             :   }
     342           2 :   if ( (0 == actual_size) &&
     343             :        (exit_if_synced) )
     344             :   {
     345           1 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     346             :                 "Databases are synchronized. Exiting\n");
     347           1 :     return;
     348             :   }
     349           1 :   if (actual_size < transaction_size / 2)
     350             :   {
     351           0 :     delay = GNUNET_TIME_STD_BACKOFF (delay);
     352             :   }
     353           1 :   else if (actual_size >= transaction_size)
     354             :   {
     355           1 :     delay = GNUNET_TIME_UNIT_ZERO;
     356             :   }
     357           1 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     358             :               "Next sync pass in %s\n",
     359             :               GNUNET_STRINGS_relative_time_to_string (delay,
     360             :                                                       GNUNET_YES));
     361           1 :   sync_task = GNUNET_SCHEDULER_add_delayed (delay,
     362             :                                             &do_sync,
     363             :                                             NULL);
     364             : }
     365             : 
     366             : 
     367             : /**
     368             :  * Set an option of type 'char *' from the command line with
     369             :  * filename expansion a la #GNUNET_STRINGS_filename_expand().
     370             :  *
     371             :  * @param ctx command line processing context
     372             :  * @param scls additional closure (will point to the `char *`,
     373             :  *             which will be allocated)
     374             :  * @param option name of the option
     375             :  * @param value actual value of the option (a string)
     376             :  * @return #GNUNET_OK
     377             :  */
     378             : static int
     379           2 : set_filename (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
     380             :               void *scls,
     381             :               const char *option,
     382             :               const char *value)
     383             : {
     384           2 :   char **val = scls;
     385             : 
     386             :   (void) ctx;
     387             :   (void) option;
     388           2 :   GNUNET_assert (NULL != value);
     389           2 :   GNUNET_free (*val);
     390           2 :   *val = GNUNET_STRINGS_filename_expand (value);
     391           2 :   return GNUNET_OK;
     392             : }
     393             : 
     394             : 
     395             : /**
     396             :  * Allow user to specify configuration file name (-s option)
     397             :  *
     398             :  * @param[out] fn set to the name of the configuration file
     399             :  */
     400             : static struct GNUNET_GETOPT_CommandLineOption
     401           1 : option_cfgfile_src (char **fn)
     402             : {
     403           1 :   struct GNUNET_GETOPT_CommandLineOption clo = {
     404             :     .shortName = 's',
     405             :     .name = "source-configuration",
     406             :     .argumentHelp = "FILENAME",
     407             :     .description = gettext_noop (
     408             :       "use configuration file FILENAME for the SOURCE database"),
     409             :     .require_argument = 1,
     410             :     .processor = &set_filename,
     411             :     .scls = (void *) fn
     412             :   };
     413             : 
     414           1 :   return clo;
     415             : }
     416             : 
     417             : 
     418             : /**
     419             :  * Allow user to specify configuration file name (-d option)
     420             :  *
     421             :  * @param[out] fn set to the name of the configuration file
     422             :  */
     423             : static struct GNUNET_GETOPT_CommandLineOption
     424           1 : option_cfgfile_dst (char **fn)
     425             : {
     426           1 :   struct GNUNET_GETOPT_CommandLineOption clo = {
     427             :     .shortName = 'd',
     428             :     .name = "destination-configuration",
     429             :     .argumentHelp = "FILENAME",
     430             :     .description = gettext_noop (
     431             :       "use configuration file FILENAME for the DESTINATION database"),
     432             :     .require_argument = 1,
     433             :     .processor = &set_filename,
     434             :     .scls = (void *) fn
     435             :   };
     436             : 
     437           1 :   return clo;
     438             : }
     439             : 
     440             : 
     441             : static struct GNUNET_CONFIGURATION_Handle *
     442           2 : load_config (const char *cfgfile)
     443             : {
     444             :   struct GNUNET_CONFIGURATION_Handle *cfg;
     445             : 
     446           2 :   cfg = GNUNET_CONFIGURATION_create ();
     447           2 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     448             :               "Loading config file: %s\n",
     449             :               cfgfile);
     450           2 :   if (GNUNET_SYSERR ==
     451           2 :       GNUNET_CONFIGURATION_load (cfg,
     452             :                                  cfgfile))
     453             :   {
     454           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     455             :                 "Malformed configuration file `%s', exit ...\n",
     456             :                 cfgfile);
     457           0 :     GNUNET_CONFIGURATION_destroy (cfg);
     458           0 :     return NULL;
     459             :   }
     460           2 :   return cfg;
     461             : }
     462             : 
     463             : 
     464             : /**
     465             :  * Shutdown task.
     466             :  *
     467             :  * @param cls NULL, unused
     468             :  */
     469             : static void
     470           1 : do_shutdown (void *cls)
     471             : {
     472           1 :   if (NULL != sync_task)
     473             :   {
     474           0 :     GNUNET_SCHEDULER_cancel (sync_task);
     475           0 :     sync_task = NULL;
     476             :   }
     477           1 : }
     478             : 
     479             : 
     480             : /**
     481             :  * Initial task.
     482             :  *
     483             :  * @param cls NULL, unused
     484             :  */
     485             : static void
     486           1 : run (void *cls)
     487             : {
     488             :   (void) cls;
     489             : 
     490           1 :   GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
     491             :                                  NULL);
     492           1 :   sync_task = GNUNET_SCHEDULER_add_now (&do_sync,
     493             :                                         NULL);
     494           1 : }
     495             : 
     496             : 
     497             : /**
     498             :  * Setup plugins in #src and #dst and #run() the main
     499             :  * logic with those plugins.
     500             :  */
     501             : static void
     502           1 : setup (struct GNUNET_CONFIGURATION_Handle *src_cfg,
     503             :        struct GNUNET_CONFIGURATION_Handle *dst_cfg)
     504             : {
     505           1 :   src = TALER_EXCHANGEDB_plugin_load (src_cfg);
     506           1 :   if (NULL == src)
     507             :   {
     508           0 :     global_ret = EXIT_NOTINSTALLED;
     509           0 :     return;
     510             :   }
     511           1 :   dst = TALER_EXCHANGEDB_plugin_load (dst_cfg);
     512           1 :   if (NULL == dst)
     513             :   {
     514           0 :     global_ret = EXIT_NOTINSTALLED;
     515           0 :     TALER_EXCHANGEDB_plugin_unload (src);
     516           0 :     src = NULL;
     517           0 :     return;
     518             :   }
     519           1 :   GNUNET_SCHEDULER_run (&run,
     520             :                         NULL);
     521           1 :   TALER_EXCHANGEDB_plugin_unload (src);
     522           1 :   src = NULL;
     523           1 :   TALER_EXCHANGEDB_plugin_unload (dst);
     524           1 :   dst = NULL;
     525             : }
     526             : 
     527             : 
     528             : /**
     529             :  * The main function of the taler-auditor-exchange tool.  This tool is used
     530             :  * to add (or remove) an exchange's master key and base URL to the auditor's
     531             :  * database.
     532             :  *
     533             :  * @param argc number of arguments from the command line
     534             :  * @param argv command line arguments
     535             :  * @return 0 ok, non-zero on error
     536             :  */
     537             : int
     538           1 : main (int argc,
     539             :       char *const *argv)
     540             : {
     541           1 :   char *src_cfgfile = NULL;
     542           1 :   char *dst_cfgfile = NULL;
     543           1 :   char *level = GNUNET_strdup ("WARNING");
     544             :   struct GNUNET_CONFIGURATION_Handle *src_cfg;
     545             :   struct GNUNET_CONFIGURATION_Handle *dst_cfg;
     546           1 :   const struct GNUNET_GETOPT_CommandLineOption options[] = {
     547           1 :     GNUNET_GETOPT_option_mandatory (
     548             :       option_cfgfile_src (&src_cfgfile)),
     549           1 :     GNUNET_GETOPT_option_mandatory (
     550             :       option_cfgfile_dst (&dst_cfgfile)),
     551           1 :     GNUNET_GETOPT_option_help (
     552             :       gettext_noop ("Make a safe copy of an exchange database")),
     553           1 :     GNUNET_GETOPT_option_uint (
     554             :       'b',
     555             :       "batch",
     556             :       "SIZE",
     557             :       gettext_noop (
     558             :         "target SIZE for a the number of records to copy in one transaction"),
     559             :       &transaction_size),
     560           1 :     GNUNET_GETOPT_option_flag (
     561             :       't',
     562             :       "terminate-when-synchronized",
     563             :       gettext_noop (
     564             :         "terminate as soon as the databases are synchronized"),
     565             :       &exit_if_synced),
     566           1 :     GNUNET_GETOPT_option_version (VERSION "-" VCS_VERSION),
     567           1 :     GNUNET_GETOPT_option_loglevel (&level),
     568             :     GNUNET_GETOPT_OPTION_END
     569             :   };
     570             : 
     571           1 :   TALER_OS_init ();
     572           1 :   TALER_gcrypt_init (); /* must trigger initialization manually at this point! */
     573             :   {
     574             :     int ret;
     575             : 
     576           1 :     ret = GNUNET_GETOPT_run ("taler-auditor-sync",
     577             :                              options,
     578             :                              argc, argv);
     579           1 :     if (GNUNET_NO == ret)
     580           0 :       return EXIT_SUCCESS;
     581           1 :     if (GNUNET_SYSERR == ret)
     582           0 :       return EXIT_INVALIDARGUMENT;
     583             :   }
     584           1 :   GNUNET_assert (GNUNET_OK ==
     585             :                  GNUNET_log_setup ("taler-auditor-sync",
     586             :                                    level,
     587             :                                    NULL));
     588           1 :   GNUNET_free (level);
     589           1 :   if (0 == strcmp (src_cfgfile,
     590             :                    dst_cfgfile))
     591             :   {
     592           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     593             :                 "Source and destination configuration files must differ!\n");
     594           0 :     return EXIT_INVALIDARGUMENT;
     595             :   }
     596           1 :   src_cfg = load_config (src_cfgfile);
     597           1 :   if (NULL == src_cfg)
     598             :   {
     599           0 :     GNUNET_free (src_cfgfile);
     600           0 :     GNUNET_free (dst_cfgfile);
     601           0 :     return EXIT_NOTCONFIGURED;
     602             :   }
     603           1 :   dst_cfg = load_config (dst_cfgfile);
     604           1 :   if (NULL == dst_cfg)
     605             :   {
     606           0 :     GNUNET_CONFIGURATION_destroy (src_cfg);
     607           0 :     GNUNET_free (src_cfgfile);
     608           0 :     GNUNET_free (dst_cfgfile);
     609           0 :     return EXIT_NOTCONFIGURED;
     610             :   }
     611           1 :   setup (src_cfg,
     612             :          dst_cfg);
     613           1 :   GNUNET_CONFIGURATION_destroy (src_cfg);
     614           1 :   GNUNET_CONFIGURATION_destroy (dst_cfg);
     615           1 :   GNUNET_free (src_cfgfile);
     616           1 :   GNUNET_free (dst_cfgfile);
     617             : 
     618           1 :   return global_ret;
     619             : }
     620             : 
     621             : 
     622             : /* end of taler-auditor-sync.c */

Generated by: LCOV version 1.14