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 Bacula® - The Network Backup Solution
17 Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
19 The main author of Bacula is Kern Sibbald, with contributions from
20 many others, a complete list can be found in the file AUTHORS.
21 This program is Free Software; you can redistribute it and/or
22 modify it under the terms of version two of the GNU General Public
23 License as published by the Free Software Foundation and included
26 This program is distributed in the hope that it will be useful, but
27 WITHOUT ANY WARRANTY; without even the implied warranty of
28 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
29 General Public License for more details.
31 You should have received a copy of the GNU General Public License
32 along with this program; if not, write to the Free Software
33 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
36 Bacula® is a registered trademark of John Walker.
37 The licensor of Bacula is the Free Software Foundation Europe
38 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
39 Switzerland, email:ftf@fsfeurope.org.
43 /* The following is necessary so that we do not include
44 * the dummy external definition of DB.
46 #define __SQL_C /* indicate that this is sql.c */
53 uint32_t bacula_db_version = 0;
55 /* List of open databases */
56 static BQUEUE db_list = {&db_list, &db_list};
57 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
59 /* -----------------------------------------------------------------------
61 * Bacula specific defines and subroutines
63 * -----------------------------------------------------------------------
67 #define DB_CONTROL_FILENAME "control.db"
68 #define DB_JOBS_FILENAME "jobs.db"
69 #define DB_POOLS_FILENAME "pools.db"
70 #define DB_MEDIA_FILENAME "media.db"
71 #define DB_JOBMEDIA_FILENAME "jobmedia.db"
72 #define DB_CLIENT_FILENAME "client.db"
73 #define DB_FILESET_FILENAME "fileset.db"
75 dbid_list::dbid_list()
77 memset(this, 0, sizeof(dbid_list));
79 DBId = (DBId_t *)malloc(max_ids * sizeof(DBId_t));
80 num_ids = num_seen = tot_ids = 0;
84 dbid_list::~dbid_list()
89 static POOLMEM *make_filename(B_DB *mdb, char *name)
94 dbf = get_pool_memory(PM_FNAME);
95 if (IsPathSeparator(working_directory[strlen(working_directory)-1])) {
100 Mmsg(dbf, "%s%c%s-%s", working_directory, sep, mdb->db_name, name);
104 int bdb_write_control_file(B_DB *mdb)
106 mdb->control.time = time(NULL);
107 lseek(mdb->cfd, 0, SEEK_SET);
108 if (write(mdb->cfd, &mdb->control, sizeof(mdb->control)) != sizeof(mdb->control)) {
109 Mmsg1(&mdb->errmsg, "Error writing control file. ERR=%s\n", strerror(errno));
110 Emsg0(M_FATAL, 0, mdb->errmsg);
117 * Retrieve database type
126 * Initialize database data structure. In principal this should
127 * never have errors, or it is really fatal.
130 db_init_database(JCR *jcr, char const *db_name, char const *db_user, char const *db_password,
131 char const *db_address, int db_port, char const *db_socket,
132 int mult_db_connections)
135 P(mutex); /* lock DB queue */
136 /* Look to see if DB already open */
137 for (mdb=NULL; (mdb=(B_DB *)qnext(&db_list, &mdb->bq)); ) {
138 if (strcmp(mdb->db_name, db_name) == 0) {
139 Dmsg2(200, "DB REopen %d %s\n", mdb->ref_count, db_name);
142 return mdb; /* already open */
146 Dmsg0(200, "db_open first time\n");
147 mdb = (B_DB *)malloc(sizeof(B_DB));
148 memset(mdb, 0, sizeof(B_DB));
149 Dmsg0(200, "DB struct init\n");
150 mdb->db_name = bstrdup(db_name);
151 mdb->errmsg = get_pool_memory(PM_EMSG);
153 mdb->cmd = get_pool_memory(PM_EMSG); /* command buffer */
155 mdb->cached_path = get_pool_memory(PM_FNAME);
156 mdb->cached_path_id = 0;
157 qinsert(&db_list, &mdb->bq); /* put db in list */
158 Dmsg0(200, "Done db_open_database()\n");
161 Jmsg(jcr, M_WARNING, 0, _("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"));
162 Jmsg(jcr, M_WARNING, 0, _("WARNING!!!! The Internal Database is NOT OPERATIONAL!\n"));
163 Jmsg(jcr, M_WARNING, 0, _("You should use SQLite, PostgreSQL, or MySQL\n"));
169 * Now actually open the database. This can generate errors,
170 * which are returned in the errmsg
173 db_open_database(JCR *jcr, B_DB *mdb)
180 Dmsg1(200, "db_open_database() %s\n", mdb->db_name);
184 if ((errstat=rwl_init(&mdb->lock)) != 0) {
185 Mmsg1(&mdb->errmsg, _("Unable to initialize DB lock. ERR=%s\n"), strerror(errstat));
190 Dmsg0(200, "make_filename\n");
191 dbf = make_filename(mdb, DB_CONTROL_FILENAME);
192 mdb->cfd = open(dbf, O_CREAT|O_RDWR, 0600);
195 Mmsg2(&mdb->errmsg, _("Unable to open Catalog DB control file %s: ERR=%s\n"),
196 dbf, strerror(errno));
200 Dmsg0(200, "DB open\n");
201 /* See if the file was previously written */
202 filend = lseek(mdb->cfd, 0, SEEK_END);
203 if (filend == 0) { /* No, initialize everything */
204 Dmsg0(200, "Init DB files\n");
205 memset(&mdb->control, 0, sizeof(mdb->control));
206 mdb->control.bdb_version = BDB_VERSION;
207 bdb_write_control_file(mdb);
209 /* Create Jobs File */
210 dbf = make_filename(mdb, DB_JOBS_FILENAME);
211 fd = open(dbf, O_CREAT|O_RDWR, 0600);
215 /* Create Pools File */
216 dbf = make_filename(mdb, DB_POOLS_FILENAME);
217 fd = open(dbf, O_CREAT|O_RDWR, 0600);
221 /* Create Media File */
222 dbf = make_filename(mdb, DB_MEDIA_FILENAME);
223 fd = open(dbf, O_CREAT|O_RDWR, 0600);
227 /* Create JobMedia File */
228 dbf = make_filename(mdb, DB_JOBMEDIA_FILENAME);
229 fd = open(dbf, O_CREAT|O_RDWR, 0600);
233 /* Create Client File */
234 dbf = make_filename(mdb, DB_CLIENT_FILENAME);
235 fd = open(dbf, O_CREAT|O_RDWR, 0600);
239 /* Create FileSet File */
240 dbf = make_filename(mdb, DB_FILESET_FILENAME);
241 fd = open(dbf, O_CREAT|O_RDWR, 0600);
246 Dmsg0(200, "Read control file\n");
248 lseek(mdb->cfd, 0, SEEK_SET); /* seek to begining of control file */
249 if (read(mdb->cfd, &mdb->control, sizeof(mdb->control)) != sizeof(mdb->control)) {
250 Mmsg1(&mdb->errmsg, _("Error reading catalog DB control file. ERR=%s\n"), strerror(errno));
252 } else if (mdb->control.bdb_version != BDB_VERSION) {
253 Mmsg2(&mdb->errmsg, _("Error, catalog DB control file wrong version. "
254 "Wanted %d, got %d\n"
255 "Please reinitialize the working directory.\n"),
256 BDB_VERSION, mdb->control.bdb_version);
259 bacula_db_version = mdb->control.bdb_version;
268 void db_close_database(JCR *jcr, B_DB *mdb)
272 if (mdb->ref_count == 0) {
274 /* close file descriptors */
286 fclose(mdb->mediafd);
288 if (mdb->jobmediafd) {
289 fclose(mdb->jobmediafd);
292 fclose(mdb->clientfd);
294 if (mdb->filesetfd) {
295 fclose(mdb->filesetfd);
297 rwl_destroy(&mdb->lock);
298 free_pool_memory(mdb->errmsg);
299 free_pool_memory(mdb->cmd);
300 free_pool_memory(mdb->cached_path);
306 void db_thread_cleanup()
310 void db_escape_string(JCR *jcr, B_DB *db, char *snew, char *old, int len)
312 memset(snew, 0, len);
313 bstrncpy(snew, old, len);
316 char *db_strerror(B_DB *mdb)
321 bool db_sql_query(B_DB *mdb, char const *query, DB_RESULT_HANDLER *result_handler, void *ctx)
327 * Open the Jobs file for reading/writing
329 int bdb_open_jobs_file(B_DB *mdb)
334 dbf = make_filename(mdb, DB_JOBS_FILENAME);
335 mdb->jobfd = fopen(dbf, "r+b");
337 Mmsg2(&mdb->errmsg, "Error opening DB Jobs file %s: ERR=%s\n",
338 dbf, strerror(errno));
339 Emsg0(M_FATAL, 0, mdb->errmsg);
349 * Open the JobMedia file for reading/writing
351 int bdb_open_jobmedia_file(B_DB *mdb)
355 if (!mdb->jobmediafd) {
356 dbf = make_filename(mdb, DB_JOBMEDIA_FILENAME);
357 mdb->jobmediafd = fopen(dbf, "r+b");
358 if (!mdb->jobmediafd) {
359 Mmsg2(&mdb->errmsg, "Error opening DB JobMedia file %s: ERR=%s\n",
360 dbf, strerror(errno));
361 Emsg0(M_FATAL, 0, mdb->errmsg);
372 * Open the Pools file for reading/writing
374 int bdb_open_pools_file(B_DB *mdb)
379 dbf = make_filename(mdb, DB_POOLS_FILENAME);
380 mdb->poolfd = fopen(dbf, "r+b");
382 Mmsg2(&mdb->errmsg, "Error opening DB Pools file %s: ERR=%s\n",
383 dbf, strerror(errno));
384 Emsg0(M_FATAL, 0, mdb->errmsg);
388 Dmsg1(200, "Opened pool file %s\n", dbf);
395 * Open the Client file for reading/writing
397 int bdb_open_client_file(B_DB *mdb)
401 if (!mdb->clientfd) {
402 dbf = make_filename(mdb, DB_CLIENT_FILENAME);
403 mdb->clientfd = fopen(dbf, "r+b");
404 if (!mdb->clientfd) {
405 Mmsg2(&mdb->errmsg, "Error opening DB Clients file %s: ERR=%s\n",
406 dbf, strerror(errno));
407 Emsg0(M_FATAL, 0, mdb->errmsg);
417 * Open the FileSet file for reading/writing
419 int bdb_open_fileset_file(B_DB *mdb)
423 if (!mdb->filesetfd) {
424 dbf = make_filename(mdb, DB_CLIENT_FILENAME);
425 mdb->filesetfd = fopen(dbf, "r+b");
426 if (!mdb->filesetfd) {
427 Mmsg2(&mdb->errmsg, "Error opening DB FileSet file %s: ERR=%s\n",
428 dbf, strerror(errno));
429 Emsg0(M_FATAL, 0, mdb->errmsg);
441 * Open the Media file for reading/writing
443 int bdb_open_media_file(B_DB *mdb)
448 dbf = make_filename(mdb, DB_MEDIA_FILENAME);
449 mdb->mediafd = fopen(dbf, "r+b");
451 Mmsg2(&mdb->errmsg, "Error opening DB Media file %s: ERR=%s\n",
452 dbf, strerror(errno));
462 void _db_lock(const char *file, int line, B_DB *mdb)
465 if ((errstat=rwl_writelock(&mdb->lock)) != 0) {
466 e_msg(file, line, M_ABORT, 0, "rwl_writelock failure. ERR=%s\n",
471 void _db_unlock(const char *file, int line, B_DB *mdb)
474 if ((errstat=rwl_writeunlock(&mdb->lock)) != 0) {
475 e_msg(file, line, M_ABORT, 0, "rwl_writeunlock failure. ERR=%s\n",
481 * Start a transaction. This groups inserts and makes things
482 * much more efficient. Usually started when inserting
485 void db_start_transaction(JCR *jcr, B_DB *mdb)
489 void db_end_transaction(JCR *jcr, B_DB *mdb)
493 bool db_update_storage_record(JCR *jcr, B_DB *mdb, STORAGE_DBR *sr)
497 db_list_pool_records(JCR *jcr, B_DB *mdb, POOL_DBR *pdbr,
498 DB_LIST_HANDLER *sendit, void *ctx, e_list_type type)
501 int db_int64_handler(void *ctx, int num_fields, char **row)
505 #endif /* HAVE_BACULA_DB */