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