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 "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 21 : 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 21 : struct GNUNET_PQ_ExecuteStatement es[] = {
98 21 : 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 21 : if (NULL ==
107 21 : (conn = GNUNET_PQ_connect_with_cfg (cfg,
108 : "exchangedb-postgres",
109 : "exchange-",
110 : es,
111 : NULL)))
112 : {
113 0 : fprintf (stderr,
114 : "Failed to initialize database.\n");
115 0 : global_ret = EXIT_NOTINSTALLED;
116 0 : return;
117 : }
118 21 : if (NULL ==
119 21 : (pg = TALER_EXCHANGEDB_connect (cfg,
120 : true)))
121 : {
122 0 : fprintf (stderr,
123 : "Failed to initialize database connection.\n");
124 0 : global_ret = EXIT_NOTINSTALLED;
125 0 : return;
126 : }
127 21 : if (GNUNET_OK !=
128 21 : GNUNET_PQ_exec_sql (conn,
129 : "procedures"))
130 : {
131 0 : GNUNET_PQ_disconnect (conn);
132 0 : fprintf (stderr,
133 : "Failed to load stored procedures.\n");
134 0 : global_ret = EXIT_NOTINSTALLED;
135 0 : return;
136 : }
137 :
138 21 : GNUNET_PQ_disconnect (conn);
139 21 : if (reset_db)
140 : {
141 18 : if (GNUNET_OK !=
142 18 : TALER_EXCHANGEDB_drop_tables (pg))
143 : {
144 0 : 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 21 : if (GNUNET_OK !=
149 42 : TALER_EXCHANGEDB_create_tables (pg,
150 42 : force_create_partitions || num_partitions
151 21 : > 0,
152 21 : num_partitions))
153 : {
154 0 : fprintf (stderr,
155 : "Failed to initialize database.\n");
156 0 : global_ret = EXIT_NOPERMISSION;
157 0 : goto exit;
158 : }
159 21 : if (gc_db || clear_shards)
160 : {
161 0 : if (GNUNET_OK !=
162 0 : TALER_EXCHANGEDB_preflight (pg))
163 : {
164 0 : fprintf (stderr,
165 : "Failed to prepare database.\n");
166 0 : global_ret = EXIT_NOPERMISSION;
167 0 : goto exit;
168 : }
169 0 : if (clear_shards)
170 : {
171 0 : if (GNUNET_OK !=
172 0 : TALER_EXCHANGEDB_delete_shard_locks (pg))
173 : {
174 0 : fprintf (stderr,
175 : "Clearing revolving shards failed!\n");
176 : }
177 : }
178 0 : if (gc_db)
179 : {
180 0 : if (GNUNET_SYSERR == TALER_EXCHANGEDB_gc (pg))
181 : {
182 0 : fprintf (stderr,
183 : "Garbage collection failed!\n");
184 : }
185 : }
186 : }
187 21 : if (inject_auditor)
188 : {
189 0 : if (GNUNET_SYSERR ==
190 0 : TALER_EXCHANGEDB_inject_auditor_triggers (pg))
191 : {
192 0 : fprintf (stderr,
193 : "Injecting auditor triggers failed!\n");
194 0 : global_ret = EXIT_FAILURE;
195 : }
196 : }
197 21 : if (NULL != disable_rules)
198 : {
199 0 : if (0 == strcasecmp (disable_rules,
200 : "exchange"))
201 : {
202 0 : fprintf (stderr,
203 : "'exchange' is not a customization rule set!\n");
204 0 : global_ret = EXIT_INVALIDARGUMENT;
205 0 : goto exit;
206 : }
207 0 : if (GNUNET_OK !=
208 0 : TALER_EXCHANGEDB_preflight (pg))
209 : {
210 0 : fprintf (stderr,
211 : "Preflight check failed!\n");
212 0 : global_ret = EXIT_FAILURE;
213 0 : goto exit;
214 : }
215 0 : switch (TALER_EXCHANGEDB_disable_rules (pg,
216 : disable_rules))
217 : {
218 0 : case GNUNET_DB_STATUS_HARD_ERROR:
219 0 : fprintf (stderr,
220 : "Hard DB error trying to disable customization!\n");
221 0 : global_ret = EXIT_FAILURE;
222 0 : goto exit;
223 0 : case GNUNET_DB_STATUS_SOFT_ERROR:
224 : /* single call, should not be possible */
225 0 : GNUNET_break (0);
226 0 : global_ret = EXIT_FAILURE;
227 0 : goto exit;
228 0 : case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
229 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
230 : "Nothing to do to disable customization schema `%s'\n",
231 : disable_rules);
232 0 : break;
233 0 : case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
234 0 : break;
235 : }
236 : }
237 21 : if (NULL != enable_rules)
238 : {
239 0 : if (0 == strcasecmp (enable_rules,
240 : "exchange"))
241 : {
242 0 : fprintf (stderr,
243 : "'exchange' is not a customization rule set!\n");
244 0 : global_ret = EXIT_INVALIDARGUMENT;
245 0 : goto exit;
246 : }
247 0 : if (GNUNET_OK !=
248 0 : TALER_EXCHANGEDB_enable_rules (pg,
249 : enable_rules))
250 : {
251 0 : fprintf (stderr,
252 : "Enabling customization `%s' failed!\n",
253 : enable_rules);
254 0 : global_ret = EXIT_FAILURE;
255 0 : goto exit;
256 : }
257 : }
258 21 : exit:
259 21 : TALER_EXCHANGEDB_disconnect (pg);
260 21 : 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 21 : main (int argc,
274 : char *const *argv)
275 : {
276 21 : const struct GNUNET_GETOPT_CommandLineOption options[] = {
277 21 : GNUNET_GETOPT_option_flag ('a',
278 : "inject-auditor",
279 : "inject auditor triggers",
280 : &inject_auditor),
281 21 : GNUNET_GETOPT_option_string ('d',
282 : "disable-customization",
283 : "SCHEMA",
284 : "remove customization rules of SCHEMA",
285 : &disable_rules),
286 21 : 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 21 : GNUNET_GETOPT_option_flag ('g',
292 : "gc",
293 : "garbage collect database",
294 : &gc_db),
295 21 : GNUNET_GETOPT_option_flag ('r',
296 : "reset",
297 : "reset database (DANGEROUS: all existing data is lost!)",
298 : &reset_db),
299 21 : 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 21 : 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 21 : 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 21 : 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 21 : if (GNUNET_SYSERR == ret)
324 0 : return EXIT_INVALIDARGUMENT;
325 21 : if (GNUNET_NO == ret)
326 0 : return EXIT_SUCCESS;
327 21 : return global_ret;
328 : }
329 :
330 :
331 : /* end of taler-exchange-dbinit.c */
|