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 (IsPathSeparator(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 * Retrieve database type
99 * Initialize database data structure. In principal this should
100 * never have errors, or it is really fatal.
103 db_init_database(JCR *jcr, char const *db_name, char const *db_user, char const *db_password,
104 char const *db_address, int db_port, char const *db_socket,
105 int mult_db_connections)
108 P(mutex); /* lock DB queue */
109 /* Look to see if DB already open */
110 for (mdb=NULL; (mdb=(B_DB *)qnext(&db_list, &mdb->bq)); ) {
111 if (strcmp(mdb->db_name, db_name) == 0) {
112 Dmsg2(200, "DB REopen %d %s\n", mdb->ref_count, db_name);
115 return mdb; /* already open */
119 Dmsg0(200, "db_open first time\n");
120 mdb = (B_DB *)malloc(sizeof(B_DB));
121 memset(mdb, 0, sizeof(B_DB));
122 Dmsg0(200, "DB struct init\n");
123 mdb->db_name = bstrdup(db_name);
124 mdb->errmsg = get_pool_memory(PM_EMSG);
126 mdb->cmd = get_pool_memory(PM_EMSG); /* command buffer */
128 mdb->cached_path = get_pool_memory(PM_FNAME);
129 mdb->cached_path_id = 0;
130 qinsert(&db_list, &mdb->bq); /* put db in list */
131 Dmsg0(200, "Done db_open_database()\n");
134 Jmsg(jcr, M_WARNING, 0, _("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"));
135 Jmsg(jcr, M_WARNING, 0, _("WARNING!!!! The Internal Database is NOT OPERATIONAL!\n"));
136 Jmsg(jcr, M_WARNING, 0, _("You should use SQLite, PostgreSQL, or MySQL\n"));
142 * Now actually open the database. This can generate errors,
143 * which are returned in the errmsg
146 db_open_database(JCR *jcr, B_DB *mdb)
153 Dmsg1(200, "db_open_database() %s\n", mdb->db_name);
157 if ((errstat=rwl_init(&mdb->lock)) != 0) {
158 Mmsg1(&mdb->errmsg, _("Unable to initialize DB lock. ERR=%s\n"), strerror(errstat));
163 Dmsg0(200, "make_filename\n");
164 dbf = make_filename(mdb, DB_CONTROL_FILENAME);
165 mdb->cfd = open(dbf, O_CREAT|O_RDWR, 0600);
168 Mmsg2(&mdb->errmsg, _("Unable to open Catalog DB control file %s: ERR=%s\n"),
169 dbf, strerror(errno));
173 Dmsg0(200, "DB open\n");
174 /* See if the file was previously written */
175 filend = lseek(mdb->cfd, 0, SEEK_END);
176 if (filend == 0) { /* No, initialize everything */
177 Dmsg0(200, "Init DB files\n");
178 memset(&mdb->control, 0, sizeof(mdb->control));
179 mdb->control.bdb_version = BDB_VERSION;
180 bdb_write_control_file(mdb);
182 /* Create Jobs File */
183 dbf = make_filename(mdb, DB_JOBS_FILENAME);
184 fd = open(dbf, O_CREAT|O_RDWR, 0600);
188 /* Create Pools File */
189 dbf = make_filename(mdb, DB_POOLS_FILENAME);
190 fd = open(dbf, O_CREAT|O_RDWR, 0600);
194 /* Create Media File */
195 dbf = make_filename(mdb, DB_MEDIA_FILENAME);
196 fd = open(dbf, O_CREAT|O_RDWR, 0600);
200 /* Create JobMedia File */
201 dbf = make_filename(mdb, DB_JOBMEDIA_FILENAME);
202 fd = open(dbf, O_CREAT|O_RDWR, 0600);
206 /* Create Client File */
207 dbf = make_filename(mdb, DB_CLIENT_FILENAME);
208 fd = open(dbf, O_CREAT|O_RDWR, 0600);
212 /* Create FileSet File */
213 dbf = make_filename(mdb, DB_FILESET_FILENAME);
214 fd = open(dbf, O_CREAT|O_RDWR, 0600);
219 Dmsg0(200, "Read control file\n");
221 lseek(mdb->cfd, 0, SEEK_SET); /* seek to begining of control file */
222 if (read(mdb->cfd, &mdb->control, sizeof(mdb->control)) != sizeof(mdb->control)) {
223 Mmsg1(&mdb->errmsg, _("Error reading catalog DB control file. ERR=%s\n"), strerror(errno));
225 } else if (mdb->control.bdb_version != BDB_VERSION) {
226 Mmsg2(&mdb->errmsg, _("Error, catalog DB control file wrong version. "
227 "Wanted %d, got %d\n"
228 "Please reinitialize the working directory.\n"),
229 BDB_VERSION, mdb->control.bdb_version);
232 bacula_db_version = mdb->control.bdb_version;
241 void db_close_database(JCR *jcr, B_DB *mdb)
245 if (mdb->ref_count == 0) {
247 /* close file descriptors */
259 fclose(mdb->mediafd);
261 if (mdb->jobmediafd) {
262 fclose(mdb->jobmediafd);
265 fclose(mdb->clientfd);
267 if (mdb->filesetfd) {
268 fclose(mdb->filesetfd);
270 rwl_destroy(&mdb->lock);
271 free_pool_memory(mdb->errmsg);
272 free_pool_memory(mdb->cmd);
273 free_pool_memory(mdb->cached_path);
280 void db_escape_string(char *snew, char *old, int len)
282 memset(snew, 0, len);
283 bstrncpy(snew, old, len);
286 char *db_strerror(B_DB *mdb)
291 int db_sql_query(B_DB *mdb, char const *query, DB_RESULT_HANDLER *result_handler, void *ctx)
297 * Open the Jobs file for reading/writing
299 int bdb_open_jobs_file(B_DB *mdb)
304 dbf = make_filename(mdb, DB_JOBS_FILENAME);
305 mdb->jobfd = fopen(dbf, "r+b");
307 Mmsg2(&mdb->errmsg, "Error opening DB Jobs file %s: ERR=%s\n",
308 dbf, strerror(errno));
309 Emsg0(M_FATAL, 0, mdb->errmsg);
319 * Open the JobMedia file for reading/writing
321 int bdb_open_jobmedia_file(B_DB *mdb)
325 if (!mdb->jobmediafd) {
326 dbf = make_filename(mdb, DB_JOBMEDIA_FILENAME);
327 mdb->jobmediafd = fopen(dbf, "r+b");
328 if (!mdb->jobmediafd) {
329 Mmsg2(&mdb->errmsg, "Error opening DB JobMedia file %s: ERR=%s\n",
330 dbf, strerror(errno));
331 Emsg0(M_FATAL, 0, mdb->errmsg);
342 * Open the Pools file for reading/writing
344 int bdb_open_pools_file(B_DB *mdb)
349 dbf = make_filename(mdb, DB_POOLS_FILENAME);
350 mdb->poolfd = fopen(dbf, "r+b");
352 Mmsg2(&mdb->errmsg, "Error opening DB Pools file %s: ERR=%s\n",
353 dbf, strerror(errno));
354 Emsg0(M_FATAL, 0, mdb->errmsg);
358 Dmsg1(200, "Opened pool file %s\n", dbf);
365 * Open the Client file for reading/writing
367 int bdb_open_client_file(B_DB *mdb)
371 if (!mdb->clientfd) {
372 dbf = make_filename(mdb, DB_CLIENT_FILENAME);
373 mdb->clientfd = fopen(dbf, "r+b");
374 if (!mdb->clientfd) {
375 Mmsg2(&mdb->errmsg, "Error opening DB Clients file %s: ERR=%s\n",
376 dbf, strerror(errno));
377 Emsg0(M_FATAL, 0, mdb->errmsg);
387 * Open the FileSet file for reading/writing
389 int bdb_open_fileset_file(B_DB *mdb)
393 if (!mdb->filesetfd) {
394 dbf = make_filename(mdb, DB_CLIENT_FILENAME);
395 mdb->filesetfd = fopen(dbf, "r+b");
396 if (!mdb->filesetfd) {
397 Mmsg2(&mdb->errmsg, "Error opening DB FileSet file %s: ERR=%s\n",
398 dbf, strerror(errno));
399 Emsg0(M_FATAL, 0, mdb->errmsg);
411 * Open the Media file for reading/writing
413 int bdb_open_media_file(B_DB *mdb)
418 dbf = make_filename(mdb, DB_MEDIA_FILENAME);
419 mdb->mediafd = fopen(dbf, "r+b");
421 Mmsg2(&mdb->errmsg, "Error opening DB Media file %s: ERR=%s\n",
422 dbf, strerror(errno));
432 void _db_lock(const char *file, int line, B_DB *mdb)
435 if ((errstat=rwl_writelock(&mdb->lock)) != 0) {
436 e_msg(file, line, M_ABORT, 0, "rwl_writelock failure. ERR=%s\n",
441 void _db_unlock(const char *file, int line, B_DB *mdb)
444 if ((errstat=rwl_writeunlock(&mdb->lock)) != 0) {
445 e_msg(file, line, M_ABORT, 0, "rwl_writeunlock failure. ERR=%s\n",
451 * Start a transaction. This groups inserts and makes things
452 * much more efficient. Usually started when inserting
455 void db_start_transaction(JCR *jcr, B_DB *mdb)
459 void db_end_transaction(JCR *jcr, B_DB *mdb)
463 bool db_update_storage_record(JCR *jcr, B_DB *mdb, STORAGE_DBR *sr)
467 db_list_pool_records(JCR *jcr, B_DB *mdb, POOL_DBR *pdbr,
468 DB_LIST_HANDLER *sendit, void *ctx, e_list_type type)
471 int db_int64_handler(void *ctx, int num_fields, char **row)
475 #endif /* HAVE_BACULA_DB */