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 plus additions
24 that are listed in the file LICENSE.
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 static POOLMEM *make_filename(B_DB *mdb, char *name)
80 dbf = get_pool_memory(PM_FNAME);
81 if (IsPathSeparator(working_directory[strlen(working_directory)-1])) {
86 Mmsg(dbf, "%s%c%s-%s", working_directory, sep, mdb->db_name, name);
90 int bdb_write_control_file(B_DB *mdb)
92 mdb->control.time = time(NULL);
93 lseek(mdb->cfd, 0, SEEK_SET);
94 if (write(mdb->cfd, &mdb->control, sizeof(mdb->control)) != sizeof(mdb->control)) {
95 Mmsg1(&mdb->errmsg, "Error writing control file. ERR=%s\n", strerror(errno));
96 Emsg0(M_FATAL, 0, mdb->errmsg);
103 * Retrieve database type
112 * Initialize database data structure. In principal this should
113 * never have errors, or it is really fatal.
116 db_init_database(JCR *jcr, char const *db_name, char const *db_user, char const *db_password,
117 char const *db_address, int db_port, char const *db_socket,
118 int mult_db_connections)
121 P(mutex); /* lock DB queue */
122 /* Look to see if DB already open */
123 for (mdb=NULL; (mdb=(B_DB *)qnext(&db_list, &mdb->bq)); ) {
124 if (strcmp(mdb->db_name, db_name) == 0) {
125 Dmsg2(200, "DB REopen %d %s\n", mdb->ref_count, db_name);
128 return mdb; /* already open */
132 Dmsg0(200, "db_open first time\n");
133 mdb = (B_DB *)malloc(sizeof(B_DB));
134 memset(mdb, 0, sizeof(B_DB));
135 Dmsg0(200, "DB struct init\n");
136 mdb->db_name = bstrdup(db_name);
137 mdb->errmsg = get_pool_memory(PM_EMSG);
139 mdb->cmd = get_pool_memory(PM_EMSG); /* command buffer */
141 mdb->cached_path = get_pool_memory(PM_FNAME);
142 mdb->cached_path_id = 0;
143 qinsert(&db_list, &mdb->bq); /* put db in list */
144 Dmsg0(200, "Done db_open_database()\n");
147 Jmsg(jcr, M_WARNING, 0, _("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"));
148 Jmsg(jcr, M_WARNING, 0, _("WARNING!!!! The Internal Database is NOT OPERATIONAL!\n"));
149 Jmsg(jcr, M_WARNING, 0, _("You should use SQLite, PostgreSQL, or MySQL\n"));
155 * Now actually open the database. This can generate errors,
156 * which are returned in the errmsg
159 db_open_database(JCR *jcr, B_DB *mdb)
166 Dmsg1(200, "db_open_database() %s\n", mdb->db_name);
170 if ((errstat=rwl_init(&mdb->lock)) != 0) {
171 Mmsg1(&mdb->errmsg, _("Unable to initialize DB lock. ERR=%s\n"), strerror(errstat));
176 Dmsg0(200, "make_filename\n");
177 dbf = make_filename(mdb, DB_CONTROL_FILENAME);
178 mdb->cfd = open(dbf, O_CREAT|O_RDWR, 0600);
181 Mmsg2(&mdb->errmsg, _("Unable to open Catalog DB control file %s: ERR=%s\n"),
182 dbf, strerror(errno));
186 Dmsg0(200, "DB open\n");
187 /* See if the file was previously written */
188 filend = lseek(mdb->cfd, 0, SEEK_END);
189 if (filend == 0) { /* No, initialize everything */
190 Dmsg0(200, "Init DB files\n");
191 memset(&mdb->control, 0, sizeof(mdb->control));
192 mdb->control.bdb_version = BDB_VERSION;
193 bdb_write_control_file(mdb);
195 /* Create Jobs File */
196 dbf = make_filename(mdb, DB_JOBS_FILENAME);
197 fd = open(dbf, O_CREAT|O_RDWR, 0600);
201 /* Create Pools File */
202 dbf = make_filename(mdb, DB_POOLS_FILENAME);
203 fd = open(dbf, O_CREAT|O_RDWR, 0600);
207 /* Create Media File */
208 dbf = make_filename(mdb, DB_MEDIA_FILENAME);
209 fd = open(dbf, O_CREAT|O_RDWR, 0600);
213 /* Create JobMedia File */
214 dbf = make_filename(mdb, DB_JOBMEDIA_FILENAME);
215 fd = open(dbf, O_CREAT|O_RDWR, 0600);
219 /* Create Client File */
220 dbf = make_filename(mdb, DB_CLIENT_FILENAME);
221 fd = open(dbf, O_CREAT|O_RDWR, 0600);
225 /* Create FileSet File */
226 dbf = make_filename(mdb, DB_FILESET_FILENAME);
227 fd = open(dbf, O_CREAT|O_RDWR, 0600);
232 Dmsg0(200, "Read control file\n");
234 lseek(mdb->cfd, 0, SEEK_SET); /* seek to begining of control file */
235 if (read(mdb->cfd, &mdb->control, sizeof(mdb->control)) != sizeof(mdb->control)) {
236 Mmsg1(&mdb->errmsg, _("Error reading catalog DB control file. ERR=%s\n"), strerror(errno));
238 } else if (mdb->control.bdb_version != BDB_VERSION) {
239 Mmsg2(&mdb->errmsg, _("Error, catalog DB control file wrong version. "
240 "Wanted %d, got %d\n"
241 "Please reinitialize the working directory.\n"),
242 BDB_VERSION, mdb->control.bdb_version);
245 bacula_db_version = mdb->control.bdb_version;
254 void db_close_database(JCR *jcr, B_DB *mdb)
258 if (mdb->ref_count == 0) {
260 /* close file descriptors */
272 fclose(mdb->mediafd);
274 if (mdb->jobmediafd) {
275 fclose(mdb->jobmediafd);
278 fclose(mdb->clientfd);
280 if (mdb->filesetfd) {
281 fclose(mdb->filesetfd);
283 rwl_destroy(&mdb->lock);
284 free_pool_memory(mdb->errmsg);
285 free_pool_memory(mdb->cmd);
286 free_pool_memory(mdb->cached_path);
293 void db_escape_string(char *snew, char *old, int len)
295 memset(snew, 0, len);
296 bstrncpy(snew, old, len);
299 char *db_strerror(B_DB *mdb)
304 int db_sql_query(B_DB *mdb, char const *query, DB_RESULT_HANDLER *result_handler, void *ctx)
310 * Open the Jobs file for reading/writing
312 int bdb_open_jobs_file(B_DB *mdb)
317 dbf = make_filename(mdb, DB_JOBS_FILENAME);
318 mdb->jobfd = fopen(dbf, "r+b");
320 Mmsg2(&mdb->errmsg, "Error opening DB Jobs file %s: ERR=%s\n",
321 dbf, strerror(errno));
322 Emsg0(M_FATAL, 0, mdb->errmsg);
332 * Open the JobMedia file for reading/writing
334 int bdb_open_jobmedia_file(B_DB *mdb)
338 if (!mdb->jobmediafd) {
339 dbf = make_filename(mdb, DB_JOBMEDIA_FILENAME);
340 mdb->jobmediafd = fopen(dbf, "r+b");
341 if (!mdb->jobmediafd) {
342 Mmsg2(&mdb->errmsg, "Error opening DB JobMedia file %s: ERR=%s\n",
343 dbf, strerror(errno));
344 Emsg0(M_FATAL, 0, mdb->errmsg);
355 * Open the Pools file for reading/writing
357 int bdb_open_pools_file(B_DB *mdb)
362 dbf = make_filename(mdb, DB_POOLS_FILENAME);
363 mdb->poolfd = fopen(dbf, "r+b");
365 Mmsg2(&mdb->errmsg, "Error opening DB Pools file %s: ERR=%s\n",
366 dbf, strerror(errno));
367 Emsg0(M_FATAL, 0, mdb->errmsg);
371 Dmsg1(200, "Opened pool file %s\n", dbf);
378 * Open the Client file for reading/writing
380 int bdb_open_client_file(B_DB *mdb)
384 if (!mdb->clientfd) {
385 dbf = make_filename(mdb, DB_CLIENT_FILENAME);
386 mdb->clientfd = fopen(dbf, "r+b");
387 if (!mdb->clientfd) {
388 Mmsg2(&mdb->errmsg, "Error opening DB Clients file %s: ERR=%s\n",
389 dbf, strerror(errno));
390 Emsg0(M_FATAL, 0, mdb->errmsg);
400 * Open the FileSet file for reading/writing
402 int bdb_open_fileset_file(B_DB *mdb)
406 if (!mdb->filesetfd) {
407 dbf = make_filename(mdb, DB_CLIENT_FILENAME);
408 mdb->filesetfd = fopen(dbf, "r+b");
409 if (!mdb->filesetfd) {
410 Mmsg2(&mdb->errmsg, "Error opening DB FileSet file %s: ERR=%s\n",
411 dbf, strerror(errno));
412 Emsg0(M_FATAL, 0, mdb->errmsg);
424 * Open the Media file for reading/writing
426 int bdb_open_media_file(B_DB *mdb)
431 dbf = make_filename(mdb, DB_MEDIA_FILENAME);
432 mdb->mediafd = fopen(dbf, "r+b");
434 Mmsg2(&mdb->errmsg, "Error opening DB Media file %s: ERR=%s\n",
435 dbf, strerror(errno));
445 void _db_lock(const char *file, int line, B_DB *mdb)
448 if ((errstat=rwl_writelock(&mdb->lock)) != 0) {
449 e_msg(file, line, M_ABORT, 0, "rwl_writelock failure. ERR=%s\n",
454 void _db_unlock(const char *file, int line, B_DB *mdb)
457 if ((errstat=rwl_writeunlock(&mdb->lock)) != 0) {
458 e_msg(file, line, M_ABORT, 0, "rwl_writeunlock failure. ERR=%s\n",
464 * Start a transaction. This groups inserts and makes things
465 * much more efficient. Usually started when inserting
468 void db_start_transaction(JCR *jcr, B_DB *mdb)
472 void db_end_transaction(JCR *jcr, B_DB *mdb)
476 bool db_update_storage_record(JCR *jcr, B_DB *mdb, STORAGE_DBR *sr)
480 db_list_pool_records(JCR *jcr, B_DB *mdb, POOL_DBR *pdbr,
481 DB_LIST_HANDLER *sendit, void *ctx, e_list_type type)
484 int db_int64_handler(void *ctx, int num_fields, char **row)
488 #endif /* HAVE_BACULA_DB */