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 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);
292 void db_thread_cleanup()
296 void db_escape_string(char *snew, char *old, int len)
298 memset(snew, 0, len);
299 bstrncpy(snew, old, len);
302 char *db_strerror(B_DB *mdb)
307 int db_sql_query(B_DB *mdb, char const *query, DB_RESULT_HANDLER *result_handler, void *ctx)
313 * Open the Jobs file for reading/writing
315 int bdb_open_jobs_file(B_DB *mdb)
320 dbf = make_filename(mdb, DB_JOBS_FILENAME);
321 mdb->jobfd = fopen(dbf, "r+b");
323 Mmsg2(&mdb->errmsg, "Error opening DB Jobs file %s: ERR=%s\n",
324 dbf, strerror(errno));
325 Emsg0(M_FATAL, 0, mdb->errmsg);
335 * Open the JobMedia file for reading/writing
337 int bdb_open_jobmedia_file(B_DB *mdb)
341 if (!mdb->jobmediafd) {
342 dbf = make_filename(mdb, DB_JOBMEDIA_FILENAME);
343 mdb->jobmediafd = fopen(dbf, "r+b");
344 if (!mdb->jobmediafd) {
345 Mmsg2(&mdb->errmsg, "Error opening DB JobMedia file %s: ERR=%s\n",
346 dbf, strerror(errno));
347 Emsg0(M_FATAL, 0, mdb->errmsg);
358 * Open the Pools file for reading/writing
360 int bdb_open_pools_file(B_DB *mdb)
365 dbf = make_filename(mdb, DB_POOLS_FILENAME);
366 mdb->poolfd = fopen(dbf, "r+b");
368 Mmsg2(&mdb->errmsg, "Error opening DB Pools file %s: ERR=%s\n",
369 dbf, strerror(errno));
370 Emsg0(M_FATAL, 0, mdb->errmsg);
374 Dmsg1(200, "Opened pool file %s\n", dbf);
381 * Open the Client file for reading/writing
383 int bdb_open_client_file(B_DB *mdb)
387 if (!mdb->clientfd) {
388 dbf = make_filename(mdb, DB_CLIENT_FILENAME);
389 mdb->clientfd = fopen(dbf, "r+b");
390 if (!mdb->clientfd) {
391 Mmsg2(&mdb->errmsg, "Error opening DB Clients file %s: ERR=%s\n",
392 dbf, strerror(errno));
393 Emsg0(M_FATAL, 0, mdb->errmsg);
403 * Open the FileSet file for reading/writing
405 int bdb_open_fileset_file(B_DB *mdb)
409 if (!mdb->filesetfd) {
410 dbf = make_filename(mdb, DB_CLIENT_FILENAME);
411 mdb->filesetfd = fopen(dbf, "r+b");
412 if (!mdb->filesetfd) {
413 Mmsg2(&mdb->errmsg, "Error opening DB FileSet file %s: ERR=%s\n",
414 dbf, strerror(errno));
415 Emsg0(M_FATAL, 0, mdb->errmsg);
427 * Open the Media file for reading/writing
429 int bdb_open_media_file(B_DB *mdb)
434 dbf = make_filename(mdb, DB_MEDIA_FILENAME);
435 mdb->mediafd = fopen(dbf, "r+b");
437 Mmsg2(&mdb->errmsg, "Error opening DB Media file %s: ERR=%s\n",
438 dbf, strerror(errno));
448 void _db_lock(const char *file, int line, B_DB *mdb)
451 if ((errstat=rwl_writelock(&mdb->lock)) != 0) {
452 e_msg(file, line, M_ABORT, 0, "rwl_writelock failure. ERR=%s\n",
457 void _db_unlock(const char *file, int line, B_DB *mdb)
460 if ((errstat=rwl_writeunlock(&mdb->lock)) != 0) {
461 e_msg(file, line, M_ABORT, 0, "rwl_writeunlock failure. ERR=%s\n",
467 * Start a transaction. This groups inserts and makes things
468 * much more efficient. Usually started when inserting
471 void db_start_transaction(JCR *jcr, B_DB *mdb)
475 void db_end_transaction(JCR *jcr, B_DB *mdb)
479 bool db_update_storage_record(JCR *jcr, B_DB *mdb, STORAGE_DBR *sr)
483 db_list_pool_records(JCR *jcr, B_DB *mdb, POOL_DBR *pdbr,
484 DB_LIST_HANDLER *sendit, void *ctx, e_list_type type)
487 int db_int64_handler(void *ctx, int num_fields, char **row)
491 #endif /* HAVE_BACULA_DB */