2 * Bacula Catalog Database routines written specifically
3 * for Bacula. Note, these routines are VERY dumb and
4 * do not provide all the functionality of an SQL database.
5 * The purpose of these routines is to ensure that Bacula
6 * can limp along if no real database is loaded on the
9 * Kern Sibbald, January MMI
17 Copyright (C) 2001-2003 Kern Sibbald and John Walker
19 This program is free software; you can redistribute it and/or
20 modify it under the terms of the GNU General Public License as
21 published by the Free Software Foundation; either version 2 of
22 the License, or (at your option) any later version.
24 This program is distributed in the hope that it will be useful,
25 but WITHOUT ANY WARRANTY; without even the implied warranty of
26 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
27 General Public License for more details.
29 You should have received a copy of the GNU General Public
30 License along with this program; if not, write to the Free
31 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
37 /* The following is necessary so that we do not include
38 * the dummy external definition of DB.
40 #define __SQL_C /* indicate that this is sql.c */
47 uint32_t bacula_db_version = 0;
49 /* Forward referenced functions */
51 extern const char *working_directory;
53 /* List of open databases */
54 static BQUEUE db_list = {&db_list, &db_list};
55 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
57 /* -----------------------------------------------------------------------
59 * Bacula specific defines and subroutines
61 * -----------------------------------------------------------------------
65 #define DB_CONTROL_FILENAME "control.db"
66 #define DB_JOBS_FILENAME "jobs.db"
67 #define DB_POOLS_FILENAME "pools.db"
68 #define DB_MEDIA_FILENAME "media.db"
69 #define DB_JOBMEDIA_FILENAME "jobmedia.db"
70 #define DB_CLIENT_FILENAME "client.db"
71 #define DB_FILESET_FILENAME "fileset.db"
73 static POOLMEM *make_filename(B_DB *mdb, char *name)
78 dbf = get_pool_memory(PM_FNAME);
79 if (working_directory[strlen(working_directory)-1] == '/') {
84 Mmsg(dbf, "%s%c%s-%s", working_directory, sep, mdb->db_name, name);
88 int bdb_write_control_file(B_DB *mdb)
90 mdb->control.time = time(NULL);
91 lseek(mdb->cfd, 0, SEEK_SET);
92 if (write(mdb->cfd, &mdb->control, sizeof(mdb->control)) != sizeof(mdb->control)) {
93 Mmsg1(&mdb->errmsg, "Error writing control file. ERR=%s\n", strerror(errno));
94 Emsg0(M_FATAL, 0, mdb->errmsg);
101 * Initialize database data structure. In principal this should
102 * never have errors, or it is really fatal.
105 db_init_database(JCR *jcr, char const *db_name, char const *db_user, char const *db_password,
106 char const *db_address, int db_port, char const *db_socket,
107 int mult_db_connections)
110 P(mutex); /* lock DB queue */
111 /* Look to see if DB already open */
112 for (mdb=NULL; (mdb=(B_DB *)qnext(&db_list, &mdb->bq)); ) {
113 if (strcmp(mdb->db_name, db_name) == 0) {
114 Dmsg2(200, "DB REopen %d %s\n", mdb->ref_count, db_name);
117 return mdb; /* already open */
120 Dmsg0(200, "db_open first time\n");
121 mdb = (B_DB *)malloc(sizeof(B_DB));
122 memset(mdb, 0, sizeof(B_DB));
123 Dmsg0(200, "DB struct init\n");
124 mdb->db_name = bstrdup(db_name);
125 mdb->errmsg = get_pool_memory(PM_EMSG);
127 mdb->cmd = get_pool_memory(PM_EMSG); /* command buffer */
129 mdb->cached_path = get_pool_memory(PM_FNAME);
130 mdb->cached_path_id = 0;
131 qinsert(&db_list, &mdb->bq); /* put db in list */
132 Dmsg0(200, "Done db_open_database()\n");
135 Jmsg(jcr, M_WARNING, 0, _("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"));
136 Jmsg(jcr, M_WARNING, 0, _("WARNING!!!! The Internal Database is NOT OPERATIONAL!\n"));
137 Jmsg(jcr, M_WARNING, 0, _("You should use SQLite, PostgreSQL, or MySQL\n"));
143 * Now actually open the database. This can generate errors,
144 * which are returned in the errmsg
147 db_open_database(JCR *jcr, B_DB *mdb)
154 Dmsg1(200, "db_open_database() %s\n", mdb->db_name);
158 if ((errstat=rwl_init(&mdb->lock)) != 0) {
159 Mmsg1(&mdb->errmsg, _("Unable to initialize DB lock. ERR=%s\n"), strerror(errstat));
164 Dmsg0(200, "make_filename\n");
165 dbf = make_filename(mdb, DB_CONTROL_FILENAME);
166 mdb->cfd = open(dbf, O_CREAT|O_RDWR, 0600);
169 Mmsg2(&mdb->errmsg, _("Unable to open Catalog DB control file %s: ERR=%s\n"),
170 dbf, strerror(errno));
174 Dmsg0(200, "DB open\n");
175 /* See if the file was previously written */
176 filend = lseek(mdb->cfd, 0, SEEK_END);
177 if (filend == 0) { /* No, initialize everything */
178 Dmsg0(200, "Init DB files\n");
179 memset(&mdb->control, 0, sizeof(mdb->control));
180 mdb->control.bdb_version = BDB_VERSION;
181 bdb_write_control_file(mdb);
183 /* Create Jobs File */
184 dbf = make_filename(mdb, DB_JOBS_FILENAME);
185 fd = open(dbf, O_CREAT|O_RDWR, 0600);
189 /* Create Pools File */
190 dbf = make_filename(mdb, DB_POOLS_FILENAME);
191 fd = open(dbf, O_CREAT|O_RDWR, 0600);
195 /* Create Media File */
196 dbf = make_filename(mdb, DB_MEDIA_FILENAME);
197 fd = open(dbf, O_CREAT|O_RDWR, 0600);
201 /* Create JobMedia File */
202 dbf = make_filename(mdb, DB_JOBMEDIA_FILENAME);
203 fd = open(dbf, O_CREAT|O_RDWR, 0600);
207 /* Create Client File */
208 dbf = make_filename(mdb, DB_CLIENT_FILENAME);
209 fd = open(dbf, O_CREAT|O_RDWR, 0600);
213 /* Create FileSet File */
214 dbf = make_filename(mdb, DB_FILESET_FILENAME);
215 fd = open(dbf, O_CREAT|O_RDWR, 0600);
220 Dmsg0(200, "Read control file\n");
222 lseek(mdb->cfd, 0, SEEK_SET); /* seek to begining of control file */
223 if (read(mdb->cfd, &mdb->control, sizeof(mdb->control)) != sizeof(mdb->control)) {
224 Mmsg1(&mdb->errmsg, _("Error reading catalog DB control file. ERR=%s\n"), strerror(errno));
226 } else if (mdb->control.bdb_version != BDB_VERSION) {
227 Mmsg2(&mdb->errmsg, _("Error, catalog DB control file wrong version. "
228 "Wanted %d, got %d\n"
229 "Please reinitialize the working directory.\n"),
230 BDB_VERSION, mdb->control.bdb_version);
233 bacula_db_version = mdb->control.bdb_version;
242 void db_close_database(JCR *jcr, B_DB *mdb)
246 if (mdb->ref_count == 0) {
248 /* close file descriptors */
260 fclose(mdb->mediafd);
262 if (mdb->jobmediafd) {
263 fclose(mdb->jobmediafd);
266 fclose(mdb->clientfd);
268 if (mdb->filesetfd) {
269 fclose(mdb->filesetfd);
271 rwl_destroy(&mdb->lock);
272 free_pool_memory(mdb->errmsg);
273 free_pool_memory(mdb->cmd);
274 free_pool_memory(mdb->cached_path);
281 void db_escape_string(char *snew, char *old, int len)
283 memset(snew, 0, len);
284 bstrncpy(snew, old, len);
287 char *db_strerror(B_DB *mdb)
292 int db_sql_query(B_DB *mdb, char const *query, DB_RESULT_HANDLER *result_handler, void *ctx)
298 * Open the Jobs file for reading/writing
300 int bdb_open_jobs_file(B_DB *mdb)
305 dbf = make_filename(mdb, DB_JOBS_FILENAME);
306 mdb->jobfd = fopen(dbf, "r+");
308 Mmsg2(&mdb->errmsg, "Error opening DB Jobs file %s: ERR=%s\n",
309 dbf, strerror(errno));
310 Emsg0(M_FATAL, 0, mdb->errmsg);
320 * Open the JobMedia file for reading/writing
322 int bdb_open_jobmedia_file(B_DB *mdb)
326 if (!mdb->jobmediafd) {
327 dbf = make_filename(mdb, DB_JOBMEDIA_FILENAME);
328 mdb->jobmediafd = fopen(dbf, "r+");
329 if (!mdb->jobmediafd) {
330 Mmsg2(&mdb->errmsg, "Error opening DB JobMedia file %s: ERR=%s\n",
331 dbf, strerror(errno));
332 Emsg0(M_FATAL, 0, mdb->errmsg);
343 * Open the Pools file for reading/writing
345 int bdb_open_pools_file(B_DB *mdb)
350 dbf = make_filename(mdb, DB_POOLS_FILENAME);
351 mdb->poolfd = fopen(dbf, "r+");
353 Mmsg2(&mdb->errmsg, "Error opening DB Pools file %s: ERR=%s\n",
354 dbf, strerror(errno));
355 Emsg0(M_FATAL, 0, mdb->errmsg);
359 Dmsg1(200, "Opened pool file %s\n", dbf);
366 * Open the Client file for reading/writing
368 int bdb_open_client_file(B_DB *mdb)
372 if (!mdb->clientfd) {
373 dbf = make_filename(mdb, DB_CLIENT_FILENAME);
374 mdb->clientfd = fopen(dbf, "r+");
375 if (!mdb->clientfd) {
376 Mmsg2(&mdb->errmsg, "Error opening DB Clients file %s: ERR=%s\n",
377 dbf, strerror(errno));
378 Emsg0(M_FATAL, 0, mdb->errmsg);
388 * Open the FileSet file for reading/writing
390 int bdb_open_fileset_file(B_DB *mdb)
394 if (!mdb->filesetfd) {
395 dbf = make_filename(mdb, DB_CLIENT_FILENAME);
396 mdb->filesetfd = fopen(dbf, "r+");
397 if (!mdb->filesetfd) {
398 Mmsg2(&mdb->errmsg, "Error opening DB FileSet file %s: ERR=%s\n",
399 dbf, strerror(errno));
400 Emsg0(M_FATAL, 0, mdb->errmsg);
412 * Open the Media file for reading/writing
414 int bdb_open_media_file(B_DB *mdb)
419 dbf = make_filename(mdb, DB_MEDIA_FILENAME);
420 mdb->mediafd = fopen(dbf, "r+");
422 Mmsg2(&mdb->errmsg, "Error opening DB Media file %s: ERR=%s\n",
423 dbf, strerror(errno));
433 void _db_lock(const char *file, int line, B_DB *mdb)
436 if ((errstat=rwl_writelock(&mdb->lock)) != 0) {
437 e_msg(file, line, M_ABORT, 0, "rwl_writelock failure. ERR=%s\n",
442 void _db_unlock(const char *file, int line, B_DB *mdb)
445 if ((errstat=rwl_writeunlock(&mdb->lock)) != 0) {
446 e_msg(file, line, M_ABORT, 0, "rwl_writeunlock failure. ERR=%s\n",
452 * Start a transaction. This groups inserts and makes things
453 * much more efficient. Usually started when inserting
456 void db_start_transaction(JCR *jcr, B_DB *mdb)
460 void db_end_transaction(JCR *jcr, B_DB *mdb)
465 #endif /* HAVE_BACULA_DB */