]> code.citadel.org Git - citadel.git/blob - citadel/utils/ctdl3264.c
ctdl3264: open and close one table at a time
[citadel.git] / citadel / utils / ctdl3264.c
1 // Attempt to convert your database from 32-bit to 64-bit.
2 // Don't run this.  It doesn't work and if you try to run it you will immediately die.
3 //
4 // Copyright (c) 2023 by the citadel.org team
5 //
6 // This program is open source software.  Use, duplication, or disclosure
7 // is subject to the terms of the GNU General Public License, version 3.
8
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <ctype.h>
12 #include <stdio.h>
13 #include <signal.h>
14 #include <sys/types.h>
15 #include <sys/socket.h>
16 #include <sys/un.h>
17 #include <netdb.h>
18 #include <string.h>
19 #include <pwd.h>
20 #include <errno.h>
21 #include <stdarg.h>
22 #include <limits.h>
23 #include <libcitadel.h>
24 #include <zlib.h>
25 #include <db.h>
26 #include "../server/sysdep.h"
27 #include "../server/citadel_defs.h"
28 #include "../server/server.h"
29 #include "../server/citadel_dirs.h"
30 #include "ctdl3264_structs.h"
31
32 static DB_ENV *dbenv;           // The DB environment (global)
33
34 // Open the various databases we'll be using.  Any database which
35 // does not exist should be created.  Note that we don't need a
36 // critical section here, because there aren't any active threads
37 // manipulating the database yet.
38 void open_databases(void) {
39         int ret;
40         int i;
41         u_int32_t flags = 0;
42         int dbversion_major, dbversion_minor, dbversion_patch;
43
44         printf( "db: open_databases() starting\n"
45                 "db:    Linked zlib: %s\n"
46                 "db: Compiled libdb: %s\n"
47                 "db:   Linked libdb: %s\n",
48                 zlibVersion(),
49                 DB_VERSION_STRING,
50                 db_version(&dbversion_major, &dbversion_minor, &dbversion_patch)
51         );
52
53         // Create synthetic integer version numbers and compare them.
54         // Never allow citserver to run with a libdb older then the one with which it was compiled.
55         int compiled_db_version = ( (DB_VERSION_MAJOR * 1000000) + (DB_VERSION_MINOR * 1000) + (DB_VERSION_PATCH) );
56         int linked_db_version = ( (dbversion_major * 1000000) + (dbversion_minor * 1000) + (dbversion_patch) );
57         if (compiled_db_version > linked_db_version) {
58                 printf( "db: citserver is running with a version of libdb older than the one with which it was compiled.\n"
59                         "db: This is an invalid configuration.  citserver will now exit to prevent data loss.");
60                 exit(CTDLEXIT_DB);
61         }
62
63         printf("db: Setting up DB environment\n");
64         ret = db_env_create(&dbenv, 0);
65         if (ret) {
66                 printf("db: db_env_create: %s\n", db_strerror(ret));
67                 printf("db: exit code %d\n", ret);
68                 exit(CTDLEXIT_DB);
69         }
70
71         // We want to specify the shared memory buffer pool cachesize, but everything else is the default.
72         ret = dbenv->set_cachesize(dbenv, 0, 64 * 1024, 0);
73         if (ret) {
74                 printf("db: set_cachesize: %s\n", db_strerror(ret));
75                 dbenv->close(dbenv, 0);
76                 printf("db: exit code %d\n", ret);
77                 exit(CTDLEXIT_DB);
78         }
79
80         if ((ret = dbenv->set_lk_detect(dbenv, DB_LOCK_DEFAULT))) {
81                 printf("db: set_lk_detect: %s\n", db_strerror(ret));
82                 dbenv->close(dbenv, 0);
83                 printf("db: exit code %d\n", ret);
84                 exit(CTDLEXIT_DB);
85         }
86
87         flags = DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE | DB_INIT_TXN | DB_INIT_LOCK | DB_THREAD | DB_INIT_LOG;
88         printf("db: dbenv->open(dbenv, %s, %d, 0)\n", ctdl_db_dir, flags);
89         ret = dbenv->open(dbenv, ctdl_db_dir, flags, 0);                                // try opening the database cleanly
90         if (ret == DB_RUNRECOVERY) {
91                 printf("db: dbenv->open: %s\n", db_strerror(ret));
92                 printf("db: attempting recovery...\n");
93                 flags |= DB_RECOVER;
94                 ret = dbenv->open(dbenv, ctdl_db_dir, flags, 0);                        // try recovery
95         }
96         if (ret == DB_RUNRECOVERY) {
97                 printf("db: dbenv->open: %s\n", db_strerror(ret));
98                 printf("db: attempting catastrophic recovery...\n");
99                 flags &= ~DB_RECOVER;
100                 flags |= DB_RECOVER_FATAL;
101                 ret = dbenv->open(dbenv, ctdl_db_dir, flags, 0);                        // try catastrophic recovery
102         }
103         if (ret) {
104                 printf("db: dbenv->open: %s\n", db_strerror(ret));
105                 dbenv->close(dbenv, 0);
106                 printf("db: exit code %d\n", ret);
107                 exit(CTDLEXIT_DB);
108         }
109 }
110
111  
112
113
114
115 // Close all of the db database files we've opened.  This can be done in a loop, since it's just a bunch of closes.
116 void close_databases(void) {
117         int i;
118         int ret;
119
120         //syslog(LOG_INFO, "db: performing final checkpoint");
121         //if ((ret = dbenv->txn_checkpoint(dbenv, 0, 0, 0))) {
122                 //syslog(LOG_ERR, "db: txn_checkpoint: %s", db_strerror(ret));
123         //}
124
125         // Close the handle.
126         ret = dbenv->close(dbenv, 0);
127         if (ret) {
128                 printf("db: DBENV->close: %s\n", db_strerror(ret));
129         }
130 }
131
132
133 void null_function(void) {
134         printf("FIXME null_function() called which means we have more work to do!\n");
135 }
136
137
138 void (*convert_functions[])(void) = {
139         null_function,          // CDB_MSGMAIN
140         null_function,          // CDB_USERS
141         null_function,          // CDB_ROOMS
142         null_function,          // CDB_FLOORTAB
143         null_function,          // CDB_MSGLISTS
144         null_function,          // CDB_VISIT
145         null_function,          // CDB_DIRECTORY
146         null_function,          // CDB_USETABLE
147         null_function,          // CDB_BIGMSGS
148         null_function,          // CDB_FULLTEXT
149         null_function,          // CDB_EUIDINDEX
150         null_function,          // CDB_USERSBYNUMBER
151         null_function,          // CDB_EXTAUTH
152         null_function           // CDB_CONFIG
153 };
154
155
156 void convert_table(int which_cdb) {
157         int ret;
158         char dbfilename[32];
159
160         printf("Converting table %d\n", which_cdb);
161
162         // Begin by opening the database (table)
163
164         DB *dbp;                                                                // One DB handle for one Citadel database
165         printf("\033[33m\033[1mdb: opening database %02x\033[0m\n", which_cdb);
166         ret = db_create(&dbp, dbenv, 0);                                        // Create a database handle
167         if (ret) {
168                 printf("db: db_create: %s\n", db_strerror(ret));
169                 printf("db: exit code %d\n", ret);
170                 exit(CTDLEXIT_DB);
171         }
172
173         snprintf(dbfilename, sizeof dbfilename, "cdb.%02x", which_cdb);                 // table names by number
174         ret = dbp->open(dbp, NULL, dbfilename, NULL, DB_BTREE, DB_AUTO_COMMIT, 0600);
175         if (ret) {
176                 printf("db: db_open[%02x]: %s\n", which_cdb, db_strerror(ret));
177                 if (ret == ENOMEM) {
178                         printf("db: You may need to tune your database; please check http://www.citadel.org for more information.\n");
179                 }
180                 printf("db: exit code %d\n", ret);
181                 exit(CTDLEXIT_DB);
182         }
183         
184         // Call the convert function (this will need some parameters later)
185         convert_functions[which_cdb]();
186
187         // Flush the logs...
188         printf("\033[33m\033[1mdb: flushing the database logs\033[0m\n");
189         if ((ret = dbenv->log_flush(dbenv, NULL))) {
190                 printf("db: log_flush: %s\n", db_strerror(ret));
191         }
192
193         // ...and close the database (table)
194         printf("\033[33m\033[1mdb: closing database %02x\033[0m\n", which_cdb);
195         ret = dbp->close(dbp, 0);
196         if (ret) {
197                 printf("db: db_close: %s\n", db_strerror(ret));
198         }
199
200 }
201
202
203 int main(int argc, char **argv) {
204         char ctdldir[PATH_MAX]=CTDLDIR;
205
206         // Check to make sure we're running on the target 64-bit system
207         if (sizeof(void *) != 8) {
208                 fprintf(stderr, "%s: this is a %ld-bit system.\n", argv[0], sizeof(void *)*8);
209                 fprintf(stderr, "%s: you must run this on a 64-bit system, onto which a 32-bit database has been copied.\n", argv[0]);
210                 exit(1);
211         }
212
213         // Parse command line
214         int a;
215         while ((a = getopt(argc, argv, "h:")) != EOF) {
216                 switch (a) {
217                 case 'h':
218                         strncpy(ctdldir, optarg, sizeof ctdldir);
219                         break;
220                 default:
221                         fprintf(stderr, "%s: usage: %s [-h server_dir]\n", argv[0], argv[0]);
222                         exit(2);
223                 }
224         }
225
226         open_databases();
227         for (int i = 0; i < MAXCDB; ++i) {
228                 convert_table(i);
229         }
230         close_databases();
231
232         exit(0);
233 }