socketpair type derived from tlsdata->ipproto
[tlspool] / tool / tlspool_dbrecovery.c
1 /* tool/tlspool_dbrecovery.c -- Run database recovery
2  *
3  * When BerkeleyDB returns DB_RUNRECOVERY, it requires explicit attention to
4  * recovery of its database(s).  This program does just that.
5  *
6  * NOTE: This is a skeleton, but the recover() procedure is empty.  It has
7  * been stated that BerkeleyDB does "normal recovery" on every open, which
8  * works especially well on the first DB->open() call with no contenders
9  * left.  For "catastrophic recovery", pre-existing backups are needed.
10  * For this reason, the program is not built, even if included in the sources.
11  *
12  * http://docs.oracle.com/cd/E17076_04/html/gsg_txn/C/recovery.html
13  *
14  * From: Rick van Rein <rick@openfortress.nl>
15  */
16
17
18 #include <stdlib.h>
19 #include <stdint.h>
20 #include <stdio.h>
21 #include <string.h>
22
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <errno.h>
28
29 #include <db.h>
30
31 #include <tlspool/internal.h>
32
33
34 const char const *usage =
35 "Usage: %s tlspool.conf [--db localid] [--db disclose] [--db trust]\n"
36 "       Where one or more --db options indicate the databases to recover.\n"
37 "       Without such options, all database in tlspool.conf are recovered.\n";
38
39
40 /* Setup and tear down management */
41 int setup_management (DB_ENV **dbenv, DB_TXN **txn) {
42         char *dbenv_dir = cfg_dbenv_dir ();
43         char *dblid_fnm = cfg_db_localid ();
44         if (dbenv_dir == NULL) {
45                 fprintf (stderr, "Please configure database environment directory\n");
46                 return 0;
47         }
48         if (dblid_fnm == NULL) {
49                 fprintf (stderr, "Please configure localid database name\n");
50                 return 0;
51         }
52         if (db_env_create (dbenv, 0) != 0) {
53                 fprintf (stderr, "Failed to create database environment");
54                 return 0;
55         }
56         if ((*dbenv)->open (*dbenv, dbenv_dir, DB_CREATE | DB_RECOVER | DB_INIT_TXN | DB_INIT_LOG | DB_INIT_LOCK | DB_THREAD | DB_INIT_MPOOL, S_IRUSR | S_IWUSR) != 0) {
57                 fprintf (stderr, "Failed to open database environment");
58                 return 0;
59         }
60         if ((*dbenv)->txn_begin (*dbenv, NULL, txn, 0) != 0) {
61                 fprintf (stderr, "Failed to start transaction\n");
62                 exit (1);
63         }
64 }
65
66
67 int open_database (char *dbname, DB_ENV *dbenv, DB_TXN *txn, DB **dbh) {
68         if (db_create (dbh, *dbenv, 0) != 0) {
69                 fprintf (stderr, "Failed to create %s database\n", dbname);
70                 return 0;
71         }
72         if ((*dbh)->set_flags (*dbh, DB_DUP) != 0) {
73                 fprintf (stderr, "Failed to setup %s database for duplicate entries\n", dbname);
74                 return 0;
75         }
76         if ((*dbh)->open (*dbh, *txn, dbname, NULL, DB_HASH, DB_THREAD, 0) != 0) {
77                 fprintf (stderr, "Failed to open %s database\n", dbname);
78                 return 0;
79         }
80         return 1;
81 }
82
83 /* Close the database */
84 void close_database (DB *db) {
85         db->close (db, 0);
86 }
87
88 /* Cleanup maangement structures */
89 void cleanup_management (DB_ENV *dbenv) {
90         dbenv->close (dbenv, 0);
91 }
92
93 /* See if the given database name is wanted for recovery */
94 int wanted (int argc_opt, char *argv_opt [], char *dbkwd) {
95         if (argc_opt == 0) {
96                 return 1;
97         }
98         while (argc_opt-- > 0) {
99                 if ((argv_opt [argc_opt][0] == '-') && (argv_opt [argc_opt][1] == '-') && (strcmp (argv_opt [argc_opt] + 2, dbkwd) == )) {
100                         return 1;
101                 }
102         }
103         return 0;
104 }
105
106
107 /* Recover a named database */
108 void recover (int argc_opt, char *argv_opt [], char *dbkwd, char *dbfname) {
109         if (wanted (argc_opt, argv_opt, dbkwd)) {
110                 dbenv->lsn_reset (dbenv, dbfname, 0);
111         }
112 }
113
114 int main (int argc, char *argv []) {
115         char *dbenvdir = NULL;
116         char *dbfname = NULL;
117         int argc_opt = argc - 2;
118         char *argv_opt = argv + 2;
119         DB_ENV *dbenv;
120         DB_TXN *txn;
121         DB *dbh;
122         //
123         // Sanity check
124         if (argc_opt < 0) {
125                 fprintf (stderr, usage, argv [0]);
126                 exit (1);
127         }
128         if (!isatty (0)) {
129                 fprintf (stderr, "This is an interactive command.  Please run it in a terminal.\n");
130                 exit (1);
131         }
132         //
133         // Initialise the modules taken from the src directory
134         dbenvdir = tlspool_configvar (NULL, "dbenv_dir");
135         if (dbenvdir == NULL) {
136                 fprintf (stderr, "Missing variable \"dbenv_dir\" in %s\n", argv [1]);
137                 exit (1);
138         }
139         //
140         // Check if database file names are provided, and print them
141         printf ("Preparing to recover the following database structures:\n");
142         printf (" * Database environment, directory %s\n", dbenvdir);
143         if (wanted (argc_opt, argv_opt, "localid")) {
144                 dbfname = cfg_db_localid ();
145         } else {
146                 dbfname = NULL;
147         }
148         if (dbfname != NULL) {
149                 printf " * Local identity database, file %s/%s\n", dbenvdir, dbfname);
150         }
151         if (wanted (argc_opt, argv_opt, "disclose")) {
152                 dbfname = cfg_db_disclose ();
153         } else {
154                 dbfname = NULL;
155         }
156         if (dbfname != NULL) {
157                 printf " * Disclosure database, file %s/%s\n", dbenvdir, dbfname);
158         }
159         if (wanted (argc_opt, argv_opt, "trust")) {
160                 dbfname = cfg_db_trust ();
161         } else {
162                 dbfname = NULL;
163         }
164         if (dbfname != NULL) {
165                 printf " * Trust anchor database, file %s/%s\n", dbenvdir, dbfname);
166         }
167         //
168         // Ask for confirmation
169         printf ("\nNote well:\n");
170         printf (" * Other programs should not access the database at during recovery\n");
171         printf (" * This program makes no backups; you could still do this now\n");
172         printf ("\nEnter \"yes\" to confirm: ");
173         if (fgets (inbuf, sizeof (inbuf) - 1, stdin)) {
174                 if (strncmp (inbuf, "yes\n") != 0) {
175                         fprintf (stderr, "Aborting, as requested.  Nothing has been done to the databases.\n");
176                         exit (1);
177                 }
178         }
179         //
180         // Start recovering
181         printf ("\nConfirmation accepted.  Recovering:\n");
182 chdir (dbenvdir);
183         if (!setup_management (&dbenv, &txn)) {
184                 exit (1);
185         }
186         recover (argc_opt, argv_opt, "localid",  cfg_db_localid  ());
187         recover (argc_opt, argv_opt, "disclose", cfg_db_disclose ());
188         recover (argc_opt, argv_opt, "trust",    cfg_db_trust    ());
189         //
190         // End recovery
191         printf ("\nIf you are happy with the foregoing, we can commit the change.\n");
192         printf ("\nEnter \"yes\" to confirm: ");
193         if (fgets (inbuf, sizeof (inbuf) - 1, stdin)) {
194                 if (strncmp (inbuf, "yes\n") != 0) {
195                         fprintf (stderr, "Aborting, as requested.  Nothing has been done to the databases.\n");
196                         if (txn->abort (txn) != 0) {
197                                 fprintf (stderr, "Transaction abort returned an error\n");
198                         }
199                         exit (1);
200                 }
201         }
202         if (txn->commit (txn, 0) != 0) {
203                 txn->abort (txn);
204                 fprintf (stderr, "Failed to commit transaction\n");
205                 exit (1);
206         } else {
207                 fprintf (stderr, "Committed transaction\n");
208         }
209         //
210         // Finish up and report success
211 success:
212         cleanup_management (dbenv);
213         return 0;
214         //
215         // Handle failure during database interactions
216 failure:
217         fprintf (stderr, "Rolling back transaction\n");
218         txn->abort (txn);
219         cleanup_management (dbenv);
220         exit (1);
221 }