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
15 Copyright (C) 2000-2006 Kern Sibbald
17 This program is free software; you can redistribute it and/or
18 modify it under the terms of the GNU General Public License
19 version 2 as amended with additional clauses defined in the
20 file LICENSE in the main source directory.
22 This program is distributed in the hope that it will be useful,
23 but WITHOUT ANY WARRANTY; without even the implied warranty of
24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 the file LICENSE for additional details.
30 /* The following is necessary so that we do not include
31 * the dummy external definition of DB.
33 #define __SQL_C /* indicate that this is sql.c */
40 uint32_t bacula_db_version = 0;
42 /* List of open databases */
43 static BQUEUE db_list = {&db_list, &db_list};
44 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
46 /* -----------------------------------------------------------------------
48 * Bacula specific defines and subroutines
50 * -----------------------------------------------------------------------
54 #define DB_CONTROL_FILENAME "control.db"
55 #define DB_JOBS_FILENAME "jobs.db"
56 #define DB_POOLS_FILENAME "pools.db"
57 #define DB_MEDIA_FILENAME "media.db"
58 #define DB_JOBMEDIA_FILENAME "jobmedia.db"
59 #define DB_CLIENT_FILENAME "client.db"
60 #define DB_FILESET_FILENAME "fileset.db"
62 static POOLMEM *make_filename(B_DB *mdb, char *name)
67 dbf = get_pool_memory(PM_FNAME);
68 if (working_directory[strlen(working_directory)-1] == '/') {
73 Mmsg(dbf, "%s%c%s-%s", working_directory, sep, mdb->db_name, name);
77 int bdb_write_control_file(B_DB *mdb)
79 mdb->control.time = time(NULL);
80 lseek(mdb->cfd, 0, SEEK_SET);
81 if (write(mdb->cfd, &mdb->control, sizeof(mdb->control)) != sizeof(mdb->control)) {
82 Mmsg1(&mdb->errmsg, "Error writing control file. ERR=%s\n", strerror(errno));
83 Emsg0(M_FATAL, 0, mdb->errmsg);
90 * Initialize database data structure. In principal this should
91 * never have errors, or it is really fatal.
94 db_init_database(JCR *jcr, char const *db_name, char const *db_user, char const *db_password,
95 char const *db_address, int db_port, char const *db_socket,
96 int mult_db_connections)
99 P(mutex); /* lock DB queue */
100 /* Look to see if DB already open */
101 for (mdb=NULL; (mdb=(B_DB *)qnext(&db_list, &mdb->bq)); ) {
102 if (strcmp(mdb->db_name, db_name) == 0) {
103 Dmsg2(200, "DB REopen %d %s\n", mdb->ref_count, db_name);
106 return mdb; /* already open */
109 Dmsg0(200, "db_open first time\n");
110 mdb = (B_DB *)malloc(sizeof(B_DB));
111 memset(mdb, 0, sizeof(B_DB));
112 Dmsg0(200, "DB struct init\n");
113 mdb->db_name = bstrdup(db_name);
114 mdb->errmsg = get_pool_memory(PM_EMSG);
116 mdb->cmd = get_pool_memory(PM_EMSG); /* command buffer */
118 mdb->cached_path = get_pool_memory(PM_FNAME);
119 mdb->cached_path_id = 0;
120 qinsert(&db_list, &mdb->bq); /* put db in list */
121 Dmsg0(200, "Done db_open_database()\n");
124 Jmsg(jcr, M_WARNING, 0, _("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"));
125 Jmsg(jcr, M_WARNING, 0, _("WARNING!!!! The Internal Database is NOT OPERATIONAL!\n"));
126 Jmsg(jcr, M_WARNING, 0, _("You should use SQLite, PostgreSQL, or MySQL\n"));
132 * Now actually open the database. This can generate errors,
133 * which are returned in the errmsg
136 db_open_database(JCR *jcr, B_DB *mdb)
143 Dmsg1(200, "db_open_database() %s\n", mdb->db_name);
147 if ((errstat=rwl_init(&mdb->lock)) != 0) {
148 Mmsg1(&mdb->errmsg, _("Unable to initialize DB lock. ERR=%s\n"), strerror(errstat));
153 Dmsg0(200, "make_filename\n");
154 dbf = make_filename(mdb, DB_CONTROL_FILENAME);
155 mdb->cfd = open(dbf, O_CREAT|O_RDWR, 0600);
158 Mmsg2(&mdb->errmsg, _("Unable to open Catalog DB control file %s: ERR=%s\n"),
159 dbf, strerror(errno));
163 Dmsg0(200, "DB open\n");
164 /* See if the file was previously written */
165 filend = lseek(mdb->cfd, 0, SEEK_END);
166 if (filend == 0) { /* No, initialize everything */
167 Dmsg0(200, "Init DB files\n");
168 memset(&mdb->control, 0, sizeof(mdb->control));
169 mdb->control.bdb_version = BDB_VERSION;
170 bdb_write_control_file(mdb);
172 /* Create Jobs File */
173 dbf = make_filename(mdb, DB_JOBS_FILENAME);
174 fd = open(dbf, O_CREAT|O_RDWR, 0600);
178 /* Create Pools File */
179 dbf = make_filename(mdb, DB_POOLS_FILENAME);
180 fd = open(dbf, O_CREAT|O_RDWR, 0600);
184 /* Create Media File */
185 dbf = make_filename(mdb, DB_MEDIA_FILENAME);
186 fd = open(dbf, O_CREAT|O_RDWR, 0600);
190 /* Create JobMedia File */
191 dbf = make_filename(mdb, DB_JOBMEDIA_FILENAME);
192 fd = open(dbf, O_CREAT|O_RDWR, 0600);
196 /* Create Client File */
197 dbf = make_filename(mdb, DB_CLIENT_FILENAME);
198 fd = open(dbf, O_CREAT|O_RDWR, 0600);
202 /* Create FileSet File */
203 dbf = make_filename(mdb, DB_FILESET_FILENAME);
204 fd = open(dbf, O_CREAT|O_RDWR, 0600);
209 Dmsg0(200, "Read control file\n");
211 lseek(mdb->cfd, 0, SEEK_SET); /* seek to begining of control file */
212 if (read(mdb->cfd, &mdb->control, sizeof(mdb->control)) != sizeof(mdb->control)) {
213 Mmsg1(&mdb->errmsg, _("Error reading catalog DB control file. ERR=%s\n"), strerror(errno));
215 } else if (mdb->control.bdb_version != BDB_VERSION) {
216 Mmsg2(&mdb->errmsg, _("Error, catalog DB control file wrong version. "
217 "Wanted %d, got %d\n"
218 "Please reinitialize the working directory.\n"),
219 BDB_VERSION, mdb->control.bdb_version);
222 bacula_db_version = mdb->control.bdb_version;
231 void db_close_database(JCR *jcr, B_DB *mdb)
235 if (mdb->ref_count == 0) {
237 /* close file descriptors */
249 fclose(mdb->mediafd);
251 if (mdb->jobmediafd) {
252 fclose(mdb->jobmediafd);
255 fclose(mdb->clientfd);
257 if (mdb->filesetfd) {
258 fclose(mdb->filesetfd);
260 rwl_destroy(&mdb->lock);
261 free_pool_memory(mdb->errmsg);
262 free_pool_memory(mdb->cmd);
263 free_pool_memory(mdb->cached_path);
270 void db_escape_string(char *snew, char *old, int len)
272 memset(snew, 0, len);
273 bstrncpy(snew, old, len);
276 char *db_strerror(B_DB *mdb)
281 int db_sql_query(B_DB *mdb, char const *query, DB_RESULT_HANDLER *result_handler, void *ctx)
287 * Open the Jobs file for reading/writing
289 int bdb_open_jobs_file(B_DB *mdb)
294 dbf = make_filename(mdb, DB_JOBS_FILENAME);
295 mdb->jobfd = fopen(dbf, "r+b");
297 Mmsg2(&mdb->errmsg, "Error opening DB Jobs file %s: ERR=%s\n",
298 dbf, strerror(errno));
299 Emsg0(M_FATAL, 0, mdb->errmsg);
309 * Open the JobMedia file for reading/writing
311 int bdb_open_jobmedia_file(B_DB *mdb)
315 if (!mdb->jobmediafd) {
316 dbf = make_filename(mdb, DB_JOBMEDIA_FILENAME);
317 mdb->jobmediafd = fopen(dbf, "r+b");
318 if (!mdb->jobmediafd) {
319 Mmsg2(&mdb->errmsg, "Error opening DB JobMedia file %s: ERR=%s\n",
320 dbf, strerror(errno));
321 Emsg0(M_FATAL, 0, mdb->errmsg);
332 * Open the Pools file for reading/writing
334 int bdb_open_pools_file(B_DB *mdb)
339 dbf = make_filename(mdb, DB_POOLS_FILENAME);
340 mdb->poolfd = fopen(dbf, "r+b");
342 Mmsg2(&mdb->errmsg, "Error opening DB Pools file %s: ERR=%s\n",
343 dbf, strerror(errno));
344 Emsg0(M_FATAL, 0, mdb->errmsg);
348 Dmsg1(200, "Opened pool file %s\n", dbf);
355 * Open the Client file for reading/writing
357 int bdb_open_client_file(B_DB *mdb)
361 if (!mdb->clientfd) {
362 dbf = make_filename(mdb, DB_CLIENT_FILENAME);
363 mdb->clientfd = fopen(dbf, "r+b");
364 if (!mdb->clientfd) {
365 Mmsg2(&mdb->errmsg, "Error opening DB Clients file %s: ERR=%s\n",
366 dbf, strerror(errno));
367 Emsg0(M_FATAL, 0, mdb->errmsg);
377 * Open the FileSet file for reading/writing
379 int bdb_open_fileset_file(B_DB *mdb)
383 if (!mdb->filesetfd) {
384 dbf = make_filename(mdb, DB_CLIENT_FILENAME);
385 mdb->filesetfd = fopen(dbf, "r+b");
386 if (!mdb->filesetfd) {
387 Mmsg2(&mdb->errmsg, "Error opening DB FileSet file %s: ERR=%s\n",
388 dbf, strerror(errno));
389 Emsg0(M_FATAL, 0, mdb->errmsg);
401 * Open the Media file for reading/writing
403 int bdb_open_media_file(B_DB *mdb)
408 dbf = make_filename(mdb, DB_MEDIA_FILENAME);
409 mdb->mediafd = fopen(dbf, "r+b");
411 Mmsg2(&mdb->errmsg, "Error opening DB Media file %s: ERR=%s\n",
412 dbf, strerror(errno));
422 void _db_lock(const char *file, int line, B_DB *mdb)
425 if ((errstat=rwl_writelock(&mdb->lock)) != 0) {
426 e_msg(file, line, M_ABORT, 0, "rwl_writelock failure. ERR=%s\n",
431 void _db_unlock(const char *file, int line, B_DB *mdb)
434 if ((errstat=rwl_writeunlock(&mdb->lock)) != 0) {
435 e_msg(file, line, M_ABORT, 0, "rwl_writeunlock failure. ERR=%s\n",
441 * Start a transaction. This groups inserts and makes things
442 * much more efficient. Usually started when inserting
445 void db_start_transaction(JCR *jcr, B_DB *mdb)
449 void db_end_transaction(JCR *jcr, B_DB *mdb)
453 bool db_update_storage_record(JCR *jcr, B_DB *mdb, STORAGE_DBR *sr)
457 db_list_pool_records(JCR *jcr, B_DB *mdb, POOL_DBR *pdbr,
458 DB_LIST_HANDLER *sendit, void *ctx, e_list_type type)
461 int db_int64_handler(void *ctx, int num_fields, char **row)
465 #endif /* HAVE_BACULA_DB */