3 * Performs recovery on OV database, if needed
4 * Performs upgrade of OV database, if needed and if '-u' used
5 * Starts ovdb_monitor, if needed
14 #include "inn/innconf.h"
15 #include "inn/messages.h"
17 #include "../storage/ovdb/ovdb.h"
18 #include "../storage/ovdb/ovdb-private.h"
20 #ifndef USE_BERKELEY_DB
22 int main(int argc UNUSED, char **argv UNUSED)
24 die("BerkeleyDB support not compiled");
27 #else /* USE_BERKELEY_DB */
29 static int open_db(DB **db, const char *name, int type)
32 #if DB_VERSION_MAJOR == 2
34 memset(&dbinfo, 0, sizeof dbinfo);
36 ret = db_open(name, type, DB_CREATE, 0666, OVDBenv, &dbinfo, db);
38 warn("db_open failed: %s", db_strerror(ret));
42 ret = db_create(db, OVDBenv, 0);
44 warn("db_create failed: %s\n", db_strerror(ret));
47 #if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
48 ret = (*db)->open(*db, NULL, name, NULL, type, DB_CREATE, 0666);
50 ret = (*db)->open(*db, name, NULL, type, DB_CREATE, 0666);
54 warn("%s->open failed: %s", name, db_strerror(ret));
61 /* Upgrade BerkeleyDB version */
62 static int upgrade_database(const char *name UNUSED)
64 #if DB_VERSION_MAJOR == 2
70 ret = db_create(&db, OVDBenv, 0);
74 notice("upgrading %s...", name);
75 ret = db->upgrade(db, name, 0);
77 warn("db->upgrade(%s) failed: %s", name, db_strerror(ret));
93 static int v1_which_db(char *group)
98 grouphash = Hash(group, strlen(group));
99 memcpy(&i, &grouphash, sizeof(i));
100 return i % ovdb_conf.numdbfiles;
103 /* Upgrade ovdb data format version 1 to 2 */
104 /* groupstats and groupsbyname are replaced by groupinfo */
105 static int upgrade_v1_to_v2(void)
107 DB *groupstats, *groupsbyname, *groupinfo, *vdb;
108 DBT key, val, ikey, ival;
110 group_id_t gid, higid = 0, higidbang = 0;
112 struct groupstats gs;
113 char group[MAXHEADERSIZE];
118 notice("upgrading data to version 2");
119 ret = open_db(&groupstats, "groupstats", DB_BTREE);
122 ret = open_db(&groupsbyname, "groupsbyname", DB_HASH);
125 ret = open_db(&groupinfo, "groupinfo", DB_BTREE);
129 memset(&key, 0, sizeof key);
130 memset(&val, 0, sizeof val);
131 memset(&ikey, 0, sizeof ikey);
132 memset(&ival, 0, sizeof ival);
134 ret = groupsbyname->cursor(groupsbyname, NULL, &cursor, 0);
138 while((ret = cursor->c_get(cursor, &key, &val, DB_NEXT)) == 0) {
139 if(key.size == 1 && *((char *)(key.data)) == '!') {
140 if(val.size == sizeof(group_id_t))
141 memcpy(&higidbang, val.data, sizeof(group_id_t));
144 if(key.size >= MAXHEADERSIZE)
146 memcpy(group, key.data, key.size);
149 if(val.size != sizeof(group_id_t))
151 memcpy(&gid, val.data, sizeof(group_id_t));
155 ikey.size = sizeof(group_id_t);
157 ret = groupstats->get(groupstats, NULL, &ikey, &ival, 0);
160 if(ival.size != sizeof(struct groupstats))
162 memcpy(&gs, ival.data, sizeof(struct groupstats));
168 gi.expired = gs.expired;
169 gi.current_gid = gi.new_gid = gid;
170 gi.current_db = gi.new_db = v1_which_db(group);
171 gi.expiregrouppid = gi.status = 0;
174 val.size = sizeof(gi);
175 ret = groupinfo->put(groupinfo, NULL, &key, &val, 0);
177 warn("groupinfo->put failed: %s", db_strerror(ret));
178 cursor->c_close(cursor);
182 cursor->c_close(cursor);
183 if(ret != DB_NOTFOUND) {
184 warn("cursor->get failed: %s", db_strerror(ret));
189 if(higidbang > higid)
192 key.data = (char *) "!groupid_freelist";
193 key.size = sizeof("!groupid_freelist");
195 val.size = sizeof(group_id_t);
197 ret = groupinfo->put(groupinfo, NULL, &key, &val, 0);
199 warn("groupinfo->put failed: %s", db_strerror(ret));
203 ret = open_db(&vdb, "version", DB_BTREE);
207 key.data = (char *) "dataversion";
208 key.size = sizeof("dataversion");
210 val.size = sizeof v2;
212 ret = vdb->put(vdb, NULL, &key, &val, 0);
214 warn("version->put failed: %s", db_strerror(ret));
218 groupstats->close(groupstats, 0);
219 groupsbyname->close(groupsbyname, 0);
220 groupinfo->close(groupinfo, 0);
223 #if DB_VERSION_MAJOR >= 3
224 ret = db_create(&groupstats, OVDBenv, 0);
227 groupstats->remove(groupstats, "groupstats", NULL, 0);
228 ret = db_create(&groupsbyname, OVDBenv, 0);
231 groupsbyname->remove(groupsbyname, "groupsbyname", NULL, 0);
233 /* This won't work if someone changed DB_DATA_DIR in DB_CONFIG */
234 p = concatpath(ovdb_conf.home, "groupstats");
237 p = concatpath(ovdb_conf.home, "groupsbyname");
245 static int check_upgrade(int do_upgrade)
253 if(do_upgrade && (ret = upgrade_database("version")))
256 ret = open_db(&db, "version", DB_BTREE);
260 memset(&key, 0, sizeof key);
261 memset(&val, 0, sizeof val);
262 key.data = (char *) "dataversion";
263 key.size = sizeof("dataversion");
264 ret = db->get(db, NULL, &key, &val, 0);
266 if(ret != DB_NOTFOUND) {
267 warn("cannot retrieve version: %s", db_strerror(ret));
272 if(ret == DB_NOTFOUND || val.size != sizeof dv) {
276 val.size = sizeof dv;
277 ret = db->put(db, NULL, &key, &val, 0);
279 warn("cannot store version: %s", db_strerror(ret));
284 memcpy(&dv, val.data, sizeof dv);
286 key.data = (char *) "numdbfiles";
287 key.size = sizeof("numdbfiles");
288 if ((ret = db->get(db, NULL, &key, &val, 0)) == 0)
289 if(val.size == sizeof(ovdb_conf.numdbfiles))
290 memcpy(&(ovdb_conf.numdbfiles), val.data, sizeof(ovdb_conf.numdbfiles));
295 ret = upgrade_database("groupstats");
298 ret = upgrade_database("groupsbyname");
302 ret = upgrade_database("groupinfo");
306 ret = upgrade_database("groupaliases");
309 for(i = 0; i < ovdb_conf.numdbfiles; i++) {
310 snprintf(name, sizeof(name), "ov%05d", i);
311 ret = upgrade_database(name);
317 if(dv > DATA_VERSION) {
318 warn("cannot open database: unknown version %d", dv);
321 if(dv < DATA_VERSION) {
323 return upgrade_v1_to_v2();
325 warn("database needs to be upgraded");
332 upgrade_environment(void)
336 ovdb_close_berkeleydb();
337 ret = ovdb_open_berkeleydb(OV_WRITE, OVDB_UPGRADE);
340 #if DB_VERSION_MAJOR >= 3
341 #if DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 0
342 ret = OVDBenv->remove(OVDBenv, ovdb_conf.home, NULL, 0);
344 ret = OVDBenv->remove(OVDBenv, ovdb_conf.home, 0);
349 ret = ovdb_open_berkeleydb(OV_WRITE, 0);
354 int main(int argc, char **argv)
356 int ret, c, do_upgrade = 0, recover_only = 0, err = 0;
360 openlog("ovdb_init", L_OPENLOG_FLAGS | LOG_PID, LOG_INN_PROG);
361 message_program_name = "ovdb_init";
363 if (!innconf_read(NULL))
366 if(strcmp(innconf->ovmethod, "ovdb"))
367 die("ovmethod not set to ovdb in inn.conf");
369 if(!ovdb_check_user())
370 die("command must be run as user " NEWSUSER);
372 chdir(innconf->pathtmp);
373 ovdb_errmode = OVDB_ERR_STDERR;
375 while((c = getopt(argc, argv, "ru")) != -1) {
384 warn("unrecognized option -%c", optopt);
389 if(recover_only && do_upgrade) {
390 warn("cannot use both -r and -u at the same time");
394 fprintf(stderr, "Usage: ovdb_init [-r|-u]\n");
398 locked = ovdb_getlock(OVDB_LOCK_EXCLUSIVE);
401 notice("database is quiescent, upgrading");
402 flags = OVDB_RECOVER | OVDB_UPGRADE;
405 notice("database is quiescent, running normal recovery");
406 flags = OVDB_RECOVER;
409 warn("database is active");
411 warn("upgrade will not be attempted");
415 die("recovery will not be attempted");
416 ovdb_getlock(OVDB_LOCK_ADMIN);
420 ret = ovdb_open_berkeleydb(OV_WRITE, flags);
421 if(ret == DB_RUNRECOVERY) {
423 die("database could not be recovered");
425 warn("database needs recovery but cannot be locked");
426 die("other processes accessing the database must exit to start"
431 die("cannot open BerkeleyDB: %s", db_strerror(ret));
437 ret = upgrade_environment();
439 die("cannot upgrade BerkeleyDB environment: %s", db_strerror(ret));
442 if(check_upgrade(do_upgrade)) {
443 ovdb_close_berkeleydb();
447 ovdb_close_berkeleydb();
450 if(ovdb_check_pidfile(OVDB_MONITOR_PIDFILE) == false) {
451 notice("starting ovdb monitor");
454 sysdie("cannot fork");
457 execl(concatpath(innconf->pathbin, "ovdb_monitor"),
458 "ovdb_monitor", SPACES, NULL);
459 syswarn("cannot exec ovdb_monitor");
462 sleep(2); /* give the monitor a chance to start */
464 warn("ovdb_monitor already running");
466 if(ovdb_conf.readserver) {
467 if(ovdb_check_pidfile(OVDB_SERVER_PIDFILE) == false) {
468 notice("starting ovdb server");
469 daemonize(innconf->pathtmp);
470 execl(concatpath(innconf->pathbin, "ovdb_server"), "ovdb_server",
472 syswarn("cannot exec ovdb_server");
475 warn("ovdb_server already running");
480 #endif /* USE_BERKELEY_DB */