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