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 */