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 (9676B)


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