Line data Source code
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 "taler/platform.h"
23 : #include <gnunet/gnunet_util_lib.h>
24 : #include "taler/taler_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 21 : 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 21 : if (NULL ==
101 21 : (pg = TALER_EXCHANGEDB_connect (cfg,
102 : true)))
103 : {
104 0 : fprintf (stderr,
105 : "Failed to initialize database plugin.\n");
106 0 : global_ret = EXIT_NOTINSTALLED;
107 0 : return;
108 : }
109 21 : if (reset_db)
110 : {
111 18 : if (GNUNET_OK !=
112 18 : TALER_EXCHANGEDB_drop_tables (pg))
113 : {
114 1 : 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 21 : if (GNUNET_OK !=
119 42 : TALER_EXCHANGEDB_create_tables (pg,
120 42 : force_create_partitions || num_partitions
121 21 : > 0,
122 21 : num_partitions))
123 : {
124 0 : fprintf (stderr,
125 : "Failed to initialize database.\n");
126 0 : global_ret = EXIT_NOPERMISSION;
127 0 : goto exit;
128 : }
129 21 : if (gc_db || clear_shards)
130 : {
131 0 : if (GNUNET_OK !=
132 0 : TALER_EXCHANGEDB_preflight (pg))
133 : {
134 0 : fprintf (stderr,
135 : "Failed to prepare database.\n");
136 0 : global_ret = EXIT_NOPERMISSION;
137 0 : goto exit;
138 : }
139 0 : if (clear_shards)
140 : {
141 0 : if (GNUNET_OK !=
142 0 : TALER_EXCHANGEDB_delete_shard_locks (pg))
143 : {
144 0 : fprintf (stderr,
145 : "Clearing revolving shards failed!\n");
146 : }
147 : }
148 0 : if (gc_db)
149 : {
150 0 : if (GNUNET_SYSERR == TALER_EXCHANGEDB_gc (pg))
151 : {
152 0 : fprintf (stderr,
153 : "Garbage collection failed!\n");
154 : }
155 : }
156 : }
157 21 : if (inject_auditor)
158 : {
159 0 : if (GNUNET_SYSERR ==
160 0 : TALER_EXCHANGEDB_inject_auditor_triggers (pg))
161 : {
162 0 : fprintf (stderr,
163 : "Injecting auditor triggers failed!\n");
164 0 : global_ret = EXIT_FAILURE;
165 : }
166 : }
167 21 : if (NULL != disable_rules)
168 : {
169 0 : if (0 == strcasecmp (disable_rules,
170 : "exchange"))
171 : {
172 0 : fprintf (stderr,
173 : "'exchange' is not a customization rule set!\n");
174 0 : global_ret = EXIT_INVALIDARGUMENT;
175 0 : goto exit;
176 : }
177 0 : if (GNUNET_OK !=
178 0 : TALER_EXCHANGEDB_preflight (pg))
179 : {
180 0 : fprintf (stderr,
181 : "Preflight check failed!\n");
182 0 : global_ret = EXIT_FAILURE;
183 0 : goto exit;
184 : }
185 0 : switch (TALER_EXCHANGEDB_disable_rules (pg,
186 : disable_rules))
187 : {
188 0 : case GNUNET_DB_STATUS_HARD_ERROR:
189 0 : fprintf (stderr,
190 : "Hard DB error trying to disable customization!\n");
191 0 : global_ret = EXIT_FAILURE;
192 0 : goto exit;
193 0 : case GNUNET_DB_STATUS_SOFT_ERROR:
194 : /* single call, should not be possible */
195 0 : GNUNET_break (0);
196 0 : global_ret = EXIT_FAILURE;
197 0 : goto exit;
198 0 : case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
199 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
200 : "Nothing to do to disable customization schema `%s'\n",
201 : disable_rules);
202 0 : break;
203 0 : case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
204 0 : break;
205 : }
206 : }
207 21 : if (NULL != enable_rules)
208 : {
209 0 : if (0 == strcasecmp (enable_rules,
210 : "exchange"))
211 : {
212 0 : fprintf (stderr,
213 : "'exchange' is not a customization rule set!\n");
214 0 : global_ret = EXIT_INVALIDARGUMENT;
215 0 : goto exit;
216 : }
217 0 : if (GNUNET_OK !=
218 0 : TALER_EXCHANGEDB_enable_rules (pg,
219 : enable_rules))
220 : {
221 0 : fprintf (stderr,
222 : "Enabling customization `%s' failed!\n",
223 : enable_rules);
224 0 : global_ret = EXIT_FAILURE;
225 0 : goto exit;
226 : }
227 : }
228 21 : exit:
229 21 : TALER_EXCHANGEDB_disconnect (pg);
230 21 : 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 21 : main (int argc,
244 : char *const *argv)
245 : {
246 21 : const struct GNUNET_GETOPT_CommandLineOption options[] = {
247 21 : GNUNET_GETOPT_option_flag ('a',
248 : "inject-auditor",
249 : "inject auditor triggers",
250 : &inject_auditor),
251 21 : GNUNET_GETOPT_option_string ('d',
252 : "disable-customization",
253 : "SCHEMA",
254 : "remove customization rules of SCHEMA",
255 : &disable_rules),
256 21 : 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 21 : GNUNET_GETOPT_option_flag ('g',
262 : "gc",
263 : "garbage collect database",
264 : &gc_db),
265 21 : GNUNET_GETOPT_option_flag ('r',
266 : "reset",
267 : "reset database (DANGEROUS: all existing data is lost!)",
268 : &reset_db),
269 21 : 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 21 : 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 21 : 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 21 : 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 21 : if (GNUNET_SYSERR == ret)
294 0 : return EXIT_INVALIDARGUMENT;
295 21 : if (GNUNET_NO == ret)
296 0 : return EXIT_SUCCESS;
297 21 : return global_ret;
298 : }
299 :
300 :
301 : /* end of taler-exchange-dbinit.c */
|