more noodling on backend detection
[citadel.git] / citadel / server / backends / common / database.c
1 // Copyright (c) 1987-2024 by the citadel.org team
2 // This program is open source software.  Use, duplication, or disclosure is subject to the GNU General Public License version 3.
3
4 // The functions in this file handle the selection and activation of a storage backend for Citadel Server.
5 // Right now, it simply activates Berkeley DB because that's the only one we have.
6
7 #include "../../sysdep.h"
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <sys/stat.h>
11 #include <stdio.h>
12 #include <dirent.h>
13 #include <libcitadel.h>
14 #include "../../ctdl_module.h"
15 #include "../../control.h"
16 #include "../../citserver.h"
17 #include "../../config.h"
18
19 void cdb_chmod_data(void);
20
21 // Header files for all available backends must be included here.
22 #include "../berkeley_db/berkeley_db.h"
23
24 // Backends must include implementations of all these functions, but with their own prefix instead of "cdb_".
25 // The initialization function of the selected backend will map them.
26 void                    (*cdb_open_databases)(void)                             = NULL;
27 void                    (*cdb_close_databases)(void)                            = NULL;
28 struct cdbdata          (*cdb_fetch)(int, const void *, int)                    = NULL;
29 int                     (*cdb_store)(int, const void *, int, void *, int)       = NULL;
30 int                     (*cdb_delete)(int, void *, int)                         = NULL;
31 struct cdbkeyval        (*cdb_next_item)(int)                                   = NULL;
32 void                    (*cdb_close_cursor)(int)                                = NULL;
33 void                    (*cdb_begin_transaction)(void)                          = NULL;
34 void                    (*cdb_end_transaction)(void)                            = NULL;
35 void                    (*cdb_check_handles)(void)                              = NULL;
36 void                    (*cdb_trunc)(int)                                       = NULL;
37 void                    (*check_handles)(void *)                                = NULL;
38 void                    (*cdb_compact)(void)                                    = NULL;
39 void                    (*cdb_checkpoint)(void)                                 = NULL;
40 void                    (*cdb_rewind)(int)                                      = NULL;
41 void                    (*cdb_tick)(void)                                       = NULL;
42
43 // This function is responsible for choosing and initializing a back end.
44 void cdb_init_backends(void) {
45
46         char *chosen_backend = NULL;
47
48         cdb_chmod_data();               // Set file level permissions so we can actually access the data files
49
50 #ifdef THIS_BUILD_CONTAINS_BDB
51         // Test for Berkeley DB (this does nothing yet -- we're preparing to test for multiple back ends in the future)
52         int fd = open(ctdl_db_dir"/cdb.00", O_RDONLY);
53         if (fd) {
54                 char junk[12];
55                 uint32_t magic;
56                 read(fd, junk, 12);     // throw the first 12 bytes away
57                 read(fd, &magic, sizeof(magic));
58                 if (magic == 0x00053162) {
59                         syslog(LOG_DEBUG, "db: found existing Citadel database in Berkeley DB format");
60                         if (!chosen_backend) {
61                                 chosen_backend = "bdb";
62                         }
63                 }
64                 close(fd);
65         }
66 #endif
67
68         // If no existing database has been detected, go with Berkeley DB.
69         if (!chosen_backend) {
70                 chosen_backend = "bdb";
71         }
72
73         // Initialize the chosen backend.
74         if (!strcmp(chosen_backend, "bdb")) {
75                 bdb_init_backend();
76         }
77 }
78
79
80 // Make sure we own all the files, because in a few milliseconds we're going to drop root privs.
81 void cdb_chmod_data(void) {
82         DIR *dp;
83         struct dirent *d;
84         char filename[PATH_MAX];
85
86         // Silently try to create the database subdirectory.  If it's already there, no problem.
87         if ((mkdir(ctdl_db_dir, 0700) != 0) && (errno != EEXIST)) {
88                 syslog(LOG_ERR, "db: database directory [%s] does not exist and could not be created: %m", ctdl_db_dir);
89                 exit(CTDLEXIT_DB);
90         }
91         if (chmod(ctdl_db_dir, 0700) != 0) {
92                 syslog(LOG_ERR, "db: unable to set database directory permissions [%s]: %m", ctdl_db_dir);
93                 exit(CTDLEXIT_DB);
94         }
95         if (chown(ctdl_db_dir, ctdluid, (-1)) != 0) {
96                 syslog(LOG_ERR, "db: unable to set the owner for [%s]: %m", ctdl_db_dir);
97                 exit(CTDLEXIT_DB);
98         }
99         dp = opendir(ctdl_db_dir);
100         if (dp != NULL) {
101                 while (d = readdir(dp), d != NULL) {
102                         if (d->d_name[0] != '.') {
103                                 int ret;
104                                 snprintf(filename, sizeof filename, "%s/%s", ctdl_db_dir, d->d_name);
105                                 ret = chmod(filename, 0600);
106                                 if (ret != 0) {
107                                         syslog(LOG_DEBUG, "db: chmod(%s, 0600) returned %d", filename, ret);
108                                 }
109                                 ret = chown(filename, ctdluid, (-1));
110                                 if (ret != 0) {
111                                         syslog(LOG_DEBUG, "db: chown(%s, ctdluid, -1) returned %d", filename, ret);
112                                 }
113                         }
114                 }
115                 closedir(dp);
116         }
117 }