exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

taler-exchange-dbinit.c (8746B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2014-2025 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 exchange-tools/taler-exchange-dbinit.c
     18  * @brief Create tables for the exchange database.
     19  * @author Florian Dold
     20  * @author Christian Grothoff
     21  */
     22 #include "platform.h"
     23 #include <gnunet/gnunet_util_lib.h>
     24 #define GNUNET_PQ_RECONNECT_CALLBACK_CLOSURE bool
     25 #include <gnunet/gnunet_pq_lib.h>
     26 #include "exchangedb_lib.h"
     27 
     28 #include "exchange-database/gc.h"
     29 #include "exchange-database/preflight.h"
     30 #include "exchange-database/create_tables.h"
     31 #include "exchange-database/delete_shard_locks.h"
     32 #include "exchange-database/disable_rules.h"
     33 #include "exchange-database/enable_rules.h"
     34 #include "exchange-database/drop_tables.h"
     35 #include "exchange-database/inject_auditor_triggers.h"
     36 
     37 /**
     38  * Return value from main().
     39  */
     40 static int global_ret;
     41 
     42 /**
     43  * -a option: inject auditor triggers
     44  */
     45 static int inject_auditor;
     46 
     47 /**
     48  * -r option: do full DB reset
     49  */
     50 static int reset_db;
     51 
     52 /**
     53  * -e option: enable custom rules
     54  */
     55 static char *enable_rules;
     56 
     57 /**
     58  * -d option: disable custom rules
     59  */
     60 static char *disable_rules;
     61 
     62 /**
     63  * -s option: clear revolving shard locks
     64  */
     65 static int clear_shards;
     66 
     67 /**
     68  * -g option: garbage collect DB
     69  */
     70 static int gc_db;
     71 
     72 /**
     73  * -P option: setup a partitioned database
     74  */
     75 static uint32_t num_partitions;
     76 
     77 /**
     78  * -f option: force partitions to be created when there is only one
     79  */
     80 static int force_create_partitions;
     81 
     82 
     83 /**
     84  * Main function that will be run.
     85  *
     86  * @param cls closure
     87  * @param args remaining command-line arguments
     88  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
     89  * @param cfg configuration
     90  */
     91 static void
     92 run (void *cls,
     93      char *const *args,
     94      const char *cfgfile,
     95      const struct GNUNET_CONFIGURATION_Handle *cfg)
     96 {
     97   struct TALER_EXCHANGEDB_PostgresContext *pg;
     98 
     99   (void) cls;
    100   (void) args;
    101   (void) cfgfile;
    102   /* An explicit reset retains its initialization behavior, even with -g.
    103      Scheduled GC must only connect to an already current schema. */
    104   pg = (gc_db && ! reset_db)
    105        ? TALER_EXCHANGEDB_connect (cfg)
    106        : TALER_EXCHANGEDB_connect_admin (cfg);
    107   if (NULL == pg)
    108   {
    109     fprintf (stderr,
    110              "Failed to initialize database connection.\n");
    111     global_ret = EXIT_NOTINSTALLED;
    112     return;
    113   }
    114   if (reset_db)
    115   {
    116     if (GNUNET_OK !=
    117         TALER_EXCHANGEDB_drop_tables (pg))
    118     {
    119       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    120                   "Could not drop tables as requested. Either database was not yet initialized, or permission denied. Consult the logs. Will still try to create new tables.\n");
    121     }
    122   }
    123   if ( ((! gc_db) || reset_db) &&
    124        (GNUNET_OK !=
    125         TALER_EXCHANGEDB_create_tables (pg,
    126                                         force_create_partitions ||
    127                                         (num_partitions > 0),
    128                                         num_partitions)) )
    129   {
    130     fprintf (stderr,
    131              "Failed to initialize database.\n");
    132     global_ret = EXIT_NOPERMISSION;
    133     goto exit;
    134   }
    135   if (gc_db || clear_shards)
    136   {
    137     if (clear_shards)
    138     {
    139       if (GNUNET_OK !=
    140           TALER_EXCHANGEDB_delete_shard_locks (pg))
    141       {
    142         fprintf (stderr,
    143                  "Clearing revolving shards failed!\n");
    144         global_ret = EXIT_FAILURE;
    145       }
    146     }
    147     if (gc_db)
    148     {
    149       if (GNUNET_SYSERR ==
    150           TALER_EXCHANGEDB_gc (pg))
    151       {
    152         fprintf (stderr,
    153                  "Garbage collection failed!\n");
    154         global_ret = EXIT_FAILURE;
    155       }
    156     }
    157   }
    158   if (inject_auditor)
    159   {
    160     if (GNUNET_SYSERR ==
    161         TALER_EXCHANGEDB_inject_auditor_triggers (pg))
    162     {
    163       fprintf (stderr,
    164                "Injecting auditor triggers failed!\n");
    165       global_ret = EXIT_FAILURE;
    166     }
    167   }
    168   if (NULL != disable_rules)
    169   {
    170     if (0 == strcasecmp (disable_rules,
    171                          "exchange"))
    172     {
    173       fprintf (stderr,
    174                "'exchange' is not a customization rule set!\n");
    175       global_ret = EXIT_INVALIDARGUMENT;
    176       goto exit;
    177     }
    178     switch (TALER_EXCHANGEDB_disable_rules (pg,
    179                                             disable_rules))
    180     {
    181     case GNUNET_DB_STATUS_HARD_ERROR:
    182       fprintf (stderr,
    183                "Hard DB error trying to disable customization!\n");
    184       global_ret = EXIT_FAILURE;
    185       goto exit;
    186     case GNUNET_DB_STATUS_SOFT_ERROR:
    187       /* single call, should not be possible */
    188       GNUNET_break (0);
    189       global_ret = EXIT_FAILURE;
    190       goto exit;
    191     case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    192       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    193                   "Nothing to do to disable customization schema `%s'\n",
    194                   disable_rules);
    195       break;
    196     case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
    197       break;
    198     }
    199   }
    200   if (NULL != enable_rules)
    201   {
    202     if (0 == strcasecmp (enable_rules,
    203                          "exchange"))
    204     {
    205       fprintf (stderr,
    206                "'exchange' is not a customization rule set!\n");
    207       global_ret = EXIT_INVALIDARGUMENT;
    208       goto exit;
    209     }
    210     if (GNUNET_OK !=
    211         TALER_EXCHANGEDB_enable_rules (pg,
    212                                        enable_rules))
    213     {
    214       fprintf (stderr,
    215                "Enabling customization `%s' failed!\n",
    216                enable_rules);
    217       global_ret = EXIT_FAILURE;
    218       goto exit;
    219     }
    220   }
    221 exit:
    222   TALER_EXCHANGEDB_disconnect (pg);
    223 }
    224 
    225 
    226 /**
    227  * The main function of the database initialization tool.
    228  * Used to initialize the Taler Exchange's database.
    229  *
    230  * @param argc number of arguments from the command line
    231  * @param argv command line arguments
    232  * @return 0 ok, non-zero on error
    233  */
    234 int
    235 main (int argc,
    236       char *const *argv)
    237 {
    238   const struct GNUNET_GETOPT_CommandLineOption options[] = {
    239     GNUNET_GETOPT_option_flag ('a',
    240                                "inject-auditor",
    241                                "inject auditor triggers",
    242                                &inject_auditor),
    243     GNUNET_GETOPT_option_string ('d',
    244                                  "disable-customization",
    245                                  "SCHEMA",
    246                                  "remove customization rules of SCHEMA",
    247                                  &disable_rules),
    248     GNUNET_GETOPT_option_string ('e',
    249                                  "enable-customization",
    250                                  "SCHEMA",
    251                                  "enable or update (to latest version) the customization rules of SCHEMA",
    252                                  &enable_rules),
    253     GNUNET_GETOPT_option_flag ('g',
    254                                "gc",
    255                                "garbage collect database",
    256                                &gc_db),
    257     GNUNET_GETOPT_option_flag ('r',
    258                                "reset",
    259                                "reset database (DANGEROUS: all existing data is lost!)",
    260                                &reset_db),
    261     GNUNET_GETOPT_option_flag ('s',
    262                                "shardunlock",
    263                                "unlock all revolving shard locks (use after system crash or shard size change while services are not running)",
    264                                &clear_shards),
    265     GNUNET_GETOPT_option_uint ('P',
    266                                "partition",
    267                                "NUMBER",
    268                                "Setup a partitioned database where each table which can be partitioned holds NUMBER partitions on a single DB node",
    269                                &num_partitions),
    270     GNUNET_GETOPT_option_flag ('f',
    271                                "force",
    272                                "Force partitions to be created if there is only one partition",
    273                                &force_create_partitions),
    274     GNUNET_GETOPT_OPTION_END
    275   };
    276   enum GNUNET_GenericReturnValue ret;
    277 
    278   ret = GNUNET_PROGRAM_run (
    279     TALER_EXCHANGE_project_data (),
    280     argc, argv,
    281     "taler-exchange-dbinit",
    282     gettext_noop ("Initialize Taler exchange database"),
    283     options,
    284     &run, NULL);
    285   if (GNUNET_SYSERR == ret)
    286     return EXIT_INVALIDARGUMENT;
    287   if (GNUNET_NO == ret)
    288     return EXIT_SUCCESS;
    289   return global_ret;
    290 }
    291 
    292 
    293 /* end of taler-exchange-dbinit.c */