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 /* Forward referenced functions */
44 extern const char *working_directory;
46 /* List of open databases */
47 static BQUEUE db_list = {&db_list, &db_list};
48 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
50 /* -----------------------------------------------------------------------
52 * Bacula specific defines and subroutines
54 * -----------------------------------------------------------------------
58 #define DB_CONTROL_FILENAME "control.db"
59 #define DB_JOBS_FILENAME "jobs.db"
60 #define DB_POOLS_FILENAME "pools.db"
61 #define DB_MEDIA_FILENAME "media.db"
62 #define DB_JOBMEDIA_FILENAME "jobmedia.db"
63 #define DB_CLIENT_FILENAME "client.db"
64 #define DB_FILESET_FILENAME "fileset.db"
66 static POOLMEM *make_filename(B_DB *mdb, char *name)
71 dbf = get_pool_memory(PM_FNAME);
72 if (working_directory[strlen(working_directory)-1] == '/') {
77 Mmsg(dbf, "%s%c%s-%s", working_directory, sep, mdb->db_name, name);
81 int bdb_write_control_file(B_DB *mdb)
83 mdb->control.time = time(NULL);
84 lseek(mdb->cfd, 0, SEEK_SET);
85 if (write(mdb->cfd, &mdb->control, sizeof(mdb->control)) != sizeof(mdb->control)) {
86 Mmsg1(&mdb->errmsg, "Error writing control file. ERR=%s\n", strerror(errno));
87 Emsg0(M_FATAL, 0, mdb->errmsg);
94 * Initialize database data structure. In principal this should
95 * never have errors, or it is really fatal.
98 db_init_database(JCR *jcr, char const *db_name, char const *db_user, char const *db_password,
99 char const *db_address, int db_port, char const *db_socket,
100 int mult_db_connections)
103 P(mutex); /* lock DB queue */
104 /* Look to see if DB already open */
105 for (mdb=NULL; (mdb=(B_DB *)qnext(&db_list, &mdb->bq)); ) {
106 if (strcmp(mdb->db_name, db_name) == 0) {
107 Dmsg2(200, "DB REopen %d %s\n", mdb->ref_count, db_name);
110 return mdb; /* already open */
113 Dmsg0(200, "db_open first time\n");
114 mdb = (B_DB *)malloc(sizeof(B_DB));
115 memset(mdb, 0, sizeof(B_DB));
116 Dmsg0(200, "DB struct init\n");
117 mdb->db_name = bstrdup(db_name);
118 mdb->errmsg = get_pool_memory(PM_EMSG);
120 mdb->cmd = get_pool_memory(PM_EMSG); /* command buffer */
122 mdb->cached_path = get_pool_memory(PM_FNAME);
123 mdb->cached_path_id = 0;
124 qinsert(&db_list, &mdb->bq); /* put db in list */
125 Dmsg0(200, "Done db_open_database()\n");
128 Jmsg(jcr, M_WARNING, 0, _("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"));
129 Jmsg(jcr, M_WARNING, 0, _("WARNING!!!! The Internal Database is NOT OPERATIONAL!\n"));
130 Jmsg(jcr, M_WARNING, 0, _("You should use SQLite, PostgreSQL, or MySQL\n"));
136 * Now actually open the database. This can generate errors,
137 * which are returned in the errmsg
140 db_open_database(JCR *jcr, B_DB *mdb)
147 Dmsg1(200, "db_open_database() %s\n", mdb->db_name);
151 if ((errstat=rwl_init(&mdb->lock)) != 0) {
152 Mmsg1(&mdb->errmsg, _("Unable to initialize DB lock. ERR=%s\n"), strerror(errstat));
157 Dmsg0(200, "make_filename\n");
158 dbf = make_filename(mdb, DB_CONTROL_FILENAME);
159 mdb->cfd = open(dbf, O_CREAT|O_RDWR, 0600);
162 Mmsg2(&mdb->errmsg, _("Unable to open Catalog DB control file %s: ERR=%s\n"),
163 dbf, strerror(errno));
167 Dmsg0(200, "DB open\n");
168 /* See if the file was previously written */
169 filend = lseek(mdb->cfd, 0, SEEK_END);
170 if (filend == 0) { /* No, initialize everything */
171 Dmsg0(200, "Init DB files\n");
172 memset(&mdb->control, 0, sizeof(mdb->control));
173 mdb->control.bdb_version = BDB_VERSION;
174 bdb_write_control_file(mdb);
176 /* Create Jobs File */
177 dbf = make_filename(mdb, DB_JOBS_FILENAME);
178 fd = open(dbf, O_CREAT|O_RDWR, 0600);
182 /* Create Pools File */
183 dbf = make_filename(mdb, DB_POOLS_FILENAME);
184 fd = open(dbf, O_CREAT|O_RDWR, 0600);
188 /* Create Media File */
189 dbf = make_filename(mdb, DB_MEDIA_FILENAME);
190 fd = open(dbf, O_CREAT|O_RDWR, 0600);
194 /* Create JobMedia File */
195 dbf = make_filename(mdb, DB_JOBMEDIA_FILENAME);
196 fd = open(dbf, O_CREAT|O_RDWR, 0600);
200 /* Create Client File */
201 dbf = make_filename(mdb, DB_CLIENT_FILENAME);
202 fd = open(dbf, O_CREAT|O_RDWR, 0600);
206 /* Create FileSet File */
207 dbf = make_filename(mdb, DB_FILESET_FILENAME);
208 fd = open(dbf, O_CREAT|O_RDWR, 0600);
213 Dmsg0(200, "Read control file\n");
215 lseek(mdb->cfd, 0, SEEK_SET); /* seek to begining of control file */
216 if (read(mdb->cfd, &mdb->control, sizeof(mdb->control)) != sizeof(mdb->control)) {
217 Mmsg1(&mdb->errmsg, _("Error reading catalog DB control file. ERR=%s\n"), strerror(errno));
219 } else if (mdb->control.bdb_version != BDB_VERSION) {
220 Mmsg2(&mdb->errmsg, _("Error, catalog DB control file wrong version. "
221 "Wanted %d, got %d\n"
222 "Please reinitialize the working directory.\n"),
223 BDB_VERSION, mdb->control.bdb_version);
226 bacula_db_version = mdb->control.bdb_version;
235 void db_close_database(JCR *jcr, B_DB *mdb)
239 if (mdb->ref_count == 0) {
241 /* close file descriptors */
253 fclose(mdb->mediafd);
255 if (mdb->jobmediafd) {
256 fclose(mdb->jobmediafd);
259 fclose(mdb->clientfd);
261 if (mdb->filesetfd) {
262 fclose(mdb->filesetfd);
264 rwl_destroy(&mdb->lock);
265 free_pool_memory(mdb->errmsg);
266 free_pool_memory(mdb->cmd);
267 free_pool_memory(mdb->cached_path);
274 void db_escape_string(char *snew, char *old, int len)
276 memset(snew, 0, len);
277 bstrncpy(snew, old, len);
280 char *db_strerror(B_DB *mdb)
285 int db_sql_query(B_DB *mdb, char const *query, DB_RESULT_HANDLER *result_handler, void *ctx)
291 * Open the Jobs file for reading/writing
293 int bdb_open_jobs_file(B_DB *mdb)
298 dbf = make_filename(mdb, DB_JOBS_FILENAME);
299 mdb->jobfd = fopen(dbf, "r+b");
301 Mmsg2(&mdb->errmsg, "Error opening DB Jobs file %s: ERR=%s\n",
302 dbf, strerror(errno));
303 Emsg0(M_FATAL, 0, mdb->errmsg);
313 * Open the JobMedia file for reading/writing
315 int bdb_open_jobmedia_file(B_DB *mdb)
319 if (!mdb->jobmediafd) {
320 dbf = make_filename(mdb, DB_JOBMEDIA_FILENAME);
321 mdb->jobmediafd = fopen(dbf, "r+b");
322 if (!mdb->jobmediafd) {
323 Mmsg2(&mdb->errmsg, "Error opening DB JobMedia file %s: ERR=%s\n",
324 dbf, strerror(errno));
325 Emsg0(M_FATAL, 0, mdb->errmsg);
336 * Open the Pools file for reading/writing
338 int bdb_open_pools_file(B_DB *mdb)
343 dbf = make_filename(mdb, DB_POOLS_FILENAME);
344 mdb->poolfd = fopen(dbf, "r+b");
346 Mmsg2(&mdb->errmsg, "Error opening DB Pools file %s: ERR=%s\n",
347 dbf, strerror(errno));
348 Emsg0(M_FATAL, 0, mdb->errmsg);
352 Dmsg1(200, "Opened pool file %s\n", dbf);
359 * Open the Client file for reading/writing
361 int bdb_open_client_file(B_DB *mdb)
365 if (!mdb->clientfd) {
366 dbf = make_filename(mdb, DB_CLIENT_FILENAME);
367 mdb->clientfd = fopen(dbf, "r+b");
368 if (!mdb->clientfd) {
369 Mmsg2(&mdb->errmsg, "Error opening DB Clients file %s: ERR=%s\n",
370 dbf, strerror(errno));
371 Emsg0(M_FATAL, 0, mdb->errmsg);
381 * Open the FileSet file for reading/writing
383 int bdb_open_fileset_file(B_DB *mdb)
387 if (!mdb->filesetfd) {
388 dbf = make_filename(mdb, DB_CLIENT_FILENAME);
389 mdb->filesetfd = fopen(dbf, "r+b");
390 if (!mdb->filesetfd) {
391 Mmsg2(&mdb->errmsg, "Error opening DB FileSet file %s: ERR=%s\n",
392 dbf, strerror(errno));
393 Emsg0(M_FATAL, 0, mdb->errmsg);
405 * Open the Media file for reading/writing
407 int bdb_open_media_file(B_DB *mdb)
412 dbf = make_filename(mdb, DB_MEDIA_FILENAME);
413 mdb->mediafd = fopen(dbf, "r+b");
415 Mmsg2(&mdb->errmsg, "Error opening DB Media file %s: ERR=%s\n",
416 dbf, strerror(errno));
426 void _db_lock(const char *file, int line, B_DB *mdb)
429 if ((errstat=rwl_writelock(&mdb->lock)) != 0) {
430 e_msg(file, line, M_ABORT, 0, "rwl_writelock failure. ERR=%s\n",
435 void _db_unlock(const char *file, int line, B_DB *mdb)
438 if ((errstat=rwl_writeunlock(&mdb->lock)) != 0) {
439 e_msg(file, line, M_ABORT, 0, "rwl_writeunlock failure. ERR=%s\n",
445 * Start a transaction. This groups inserts and makes things
446 * much more efficient. Usually started when inserting
449 void db_start_transaction(JCR *jcr, B_DB *mdb)
453 void db_end_transaction(JCR *jcr, B_DB *mdb)
457 bool db_update_storage_record(JCR *jcr, B_DB *mdb, STORAGE_DBR *sr)
461 db_list_pool_records(JCR *jcr, B_DB *mdb, POOL_DBR *pdbr,
462 DB_LIST_HANDLER *sendit, void *ctx, e_list_type type)
465 #endif /* HAVE_BACULA_DB */