2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version two of the GNU General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
29 * Bacula Catalog Database routines written specifically
30 * for Bacula. Note, these routines are VERY dumb and
31 * do not provide all the functionality of an SQL database.
32 * The purpose of these routines is to ensure that Bacula
33 * can limp along if no real database is loaded on the
36 * Kern Sibbald, January MMI
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;
57 /* List of open databases */
58 static BQUEUE db_list = {&db_list, &db_list};
59 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
61 /* -----------------------------------------------------------------------
63 * Bacula specific defines and subroutines
65 * -----------------------------------------------------------------------
69 #define DB_CONTROL_FILENAME "control.db"
70 #define DB_JOBS_FILENAME "jobs.db"
71 #define DB_POOLS_FILENAME "pools.db"
72 #define DB_MEDIA_FILENAME "media.db"
73 #define DB_JOBMEDIA_FILENAME "jobmedia.db"
74 #define DB_CLIENT_FILENAME "client.db"
75 #define DB_FILESET_FILENAME "fileset.db"
78 B_DB *db_init(JCR *jcr, const char *db_driver, const char *db_name, const char *db_user,
79 const char *db_password, const char *db_address, int db_port,
80 const char *db_socket, int mult_db_connections)
82 return db_init_database(jcr, db_name, db_user, db_password, db_address,
83 db_port, db_socket, mult_db_connections);
87 dbid_list::dbid_list()
89 memset(this, 0, sizeof(dbid_list));
91 DBId = (DBId_t *)malloc(max_ids * sizeof(DBId_t));
92 num_ids = num_seen = tot_ids = 0;
96 dbid_list::~dbid_list()
101 static POOLMEM *make_filename(B_DB *mdb, const char *name)
106 dbf = get_pool_memory(PM_FNAME);
107 if (IsPathSeparator(working_directory[strlen(working_directory)-1])) {
112 Mmsg(dbf, "%s%c%s-%s", working_directory, sep, mdb->db_name, name);
116 int bdb_write_control_file(B_DB *mdb)
118 mdb->control.time = time(NULL);
119 lseek(mdb->cfd, 0, SEEK_SET);
120 if (write(mdb->cfd, &mdb->control, sizeof(mdb->control)) != sizeof(mdb->control)) {
121 Mmsg1(&mdb->errmsg, "Error writing control file. ERR=%s\n", strerror(errno));
122 Emsg0(M_FATAL, 0, mdb->errmsg);
129 * Retrieve database type
138 * Initialize database data structure. In principal this should
139 * never have errors, or it is really fatal.
142 db_init_database(JCR *jcr, char const *db_name, char const *db_user, char const *db_password,
143 char const *db_address, int db_port, char const *db_socket,
144 int mult_db_connections)
147 P(mutex); /* lock DB queue */
148 /* Look to see if DB already open */
149 for (mdb=NULL; (mdb=(B_DB *)qnext(&db_list, &mdb->bq)); ) {
150 if (strcmp(mdb->db_name, db_name) == 0) {
151 Dmsg2(200, "DB REopen %d %s\n", mdb->ref_count, db_name);
154 return mdb; /* already open */
158 Dmsg0(200, "db_open first time\n");
159 mdb = (B_DB *)malloc(sizeof(B_DB));
160 memset(mdb, 0, sizeof(B_DB));
161 Dmsg0(200, "DB struct init\n");
162 mdb->db_name = bstrdup(db_name);
163 mdb->errmsg = get_pool_memory(PM_EMSG);
165 mdb->cmd = get_pool_memory(PM_EMSG); /* command buffer */
167 mdb->cached_path = get_pool_memory(PM_FNAME);
168 mdb->cached_path_id = 0;
169 qinsert(&db_list, &mdb->bq); /* put db in list */
170 Dmsg0(200, "Done db_open_database()\n");
173 Jmsg(jcr, M_WARNING, 0, _("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"));
174 Jmsg(jcr, M_WARNING, 0, _("WARNING!!!! The Internal Database is NOT OPERATIONAL!\n"));
175 Jmsg(jcr, M_WARNING, 0, _("You should use SQLite, PostgreSQL, or MySQL\n"));
181 * Now actually open the database. This can generate errors,
182 * which are returned in the errmsg
185 db_open_database(JCR *jcr, B_DB *mdb)
192 Dmsg1(200, "db_open_database() %s\n", mdb->db_name);
196 if ((errstat=rwl_init(&mdb->lock)) != 0) {
197 Mmsg1(&mdb->errmsg, _("Unable to initialize DB lock. ERR=%s\n"), strerror(errstat));
202 Dmsg0(200, "make_filename\n");
203 dbf = make_filename(mdb, DB_CONTROL_FILENAME);
204 mdb->cfd = open(dbf, O_CREAT|O_RDWR, 0600);
207 Mmsg2(&mdb->errmsg, _("Unable to open Catalog DB control file %s: ERR=%s\n"),
208 dbf, strerror(errno));
212 Dmsg0(200, "DB open\n");
213 /* See if the file was previously written */
214 filend = lseek(mdb->cfd, 0, SEEK_END);
215 if (filend == 0) { /* No, initialize everything */
216 Dmsg0(200, "Init DB files\n");
217 memset(&mdb->control, 0, sizeof(mdb->control));
218 mdb->control.bdb_version = BDB_VERSION;
219 bdb_write_control_file(mdb);
221 /* Create Jobs File */
222 dbf = make_filename(mdb, DB_JOBS_FILENAME);
223 fd = open(dbf, O_CREAT|O_RDWR, 0600);
227 /* Create Pools File */
228 dbf = make_filename(mdb, DB_POOLS_FILENAME);
229 fd = open(dbf, O_CREAT|O_RDWR, 0600);
233 /* Create Media File */
234 dbf = make_filename(mdb, DB_MEDIA_FILENAME);
235 fd = open(dbf, O_CREAT|O_RDWR, 0600);
239 /* Create JobMedia File */
240 dbf = make_filename(mdb, DB_JOBMEDIA_FILENAME);
241 fd = open(dbf, O_CREAT|O_RDWR, 0600);
245 /* Create Client File */
246 dbf = make_filename(mdb, DB_CLIENT_FILENAME);
247 fd = open(dbf, O_CREAT|O_RDWR, 0600);
251 /* Create FileSet File */
252 dbf = make_filename(mdb, DB_FILESET_FILENAME);
253 fd = open(dbf, O_CREAT|O_RDWR, 0600);
258 Dmsg0(200, "Read control file\n");
260 lseek(mdb->cfd, 0, SEEK_SET); /* seek to begining of control file */
261 if (read(mdb->cfd, &mdb->control, sizeof(mdb->control)) != sizeof(mdb->control)) {
262 Mmsg1(&mdb->errmsg, _("Error reading catalog DB control file. ERR=%s\n"), strerror(errno));
264 } else if (mdb->control.bdb_version != BDB_VERSION) {
265 Mmsg2(&mdb->errmsg, _("Error, catalog DB control file wrong version. "
266 "Wanted %d, got %d\n"
267 "Please reinitialize the working directory.\n"),
268 BDB_VERSION, mdb->control.bdb_version);
271 bacula_db_version = mdb->control.bdb_version;
280 void db_close_database(JCR *jcr, B_DB *mdb)
284 if (mdb->ref_count == 0) {
286 /* close file descriptors */
298 fclose(mdb->mediafd);
300 if (mdb->jobmediafd) {
301 fclose(mdb->jobmediafd);
304 fclose(mdb->clientfd);
306 if (mdb->filesetfd) {
307 fclose(mdb->filesetfd);
309 rwl_destroy(&mdb->lock);
310 free_pool_memory(mdb->errmsg);
311 free_pool_memory(mdb->cmd);
312 free_pool_memory(mdb->cached_path);
318 void db_thread_cleanup()
322 void db_escape_string(JCR *jcr, B_DB *db, char *snew, char *old, int len)
324 memset(snew, 0, len);
325 bstrncpy(snew, old, len);
328 char *db_strerror(B_DB *mdb)
333 bool db_sql_query(B_DB *mdb, char const *query, DB_RESULT_HANDLER *result_handler, void *ctx)
339 * Open the Jobs file for reading/writing
341 int bdb_open_jobs_file(B_DB *mdb)
346 dbf = make_filename(mdb, DB_JOBS_FILENAME);
347 mdb->jobfd = fopen(dbf, "r+b");
349 Mmsg2(&mdb->errmsg, "Error opening DB Jobs file %s: ERR=%s\n",
350 dbf, strerror(errno));
351 Emsg0(M_FATAL, 0, mdb->errmsg);
361 * Open the JobMedia file for reading/writing
363 int bdb_open_jobmedia_file(B_DB *mdb)
367 if (!mdb->jobmediafd) {
368 dbf = make_filename(mdb, DB_JOBMEDIA_FILENAME);
369 mdb->jobmediafd = fopen(dbf, "r+b");
370 if (!mdb->jobmediafd) {
371 Mmsg2(&mdb->errmsg, "Error opening DB JobMedia file %s: ERR=%s\n",
372 dbf, strerror(errno));
373 Emsg0(M_FATAL, 0, mdb->errmsg);
384 * Open the Pools file for reading/writing
386 int bdb_open_pools_file(B_DB *mdb)
391 dbf = make_filename(mdb, DB_POOLS_FILENAME);
392 mdb->poolfd = fopen(dbf, "r+b");
394 Mmsg2(&mdb->errmsg, "Error opening DB Pools file %s: ERR=%s\n",
395 dbf, strerror(errno));
396 Emsg0(M_FATAL, 0, mdb->errmsg);
400 Dmsg1(200, "Opened pool file %s\n", dbf);
407 * Open the Client file for reading/writing
409 int bdb_open_client_file(B_DB *mdb)
413 if (!mdb->clientfd) {
414 dbf = make_filename(mdb, DB_CLIENT_FILENAME);
415 mdb->clientfd = fopen(dbf, "r+b");
416 if (!mdb->clientfd) {
417 Mmsg2(&mdb->errmsg, "Error opening DB Clients file %s: ERR=%s\n",
418 dbf, strerror(errno));
419 Emsg0(M_FATAL, 0, mdb->errmsg);
429 * Open the FileSet file for reading/writing
431 int bdb_open_fileset_file(B_DB *mdb)
435 if (!mdb->filesetfd) {
436 dbf = make_filename(mdb, DB_CLIENT_FILENAME);
437 mdb->filesetfd = fopen(dbf, "r+b");
438 if (!mdb->filesetfd) {
439 Mmsg2(&mdb->errmsg, "Error opening DB FileSet file %s: ERR=%s\n",
440 dbf, strerror(errno));
441 Emsg0(M_FATAL, 0, mdb->errmsg);
453 * Open the Media file for reading/writing
455 int bdb_open_media_file(B_DB *mdb)
460 dbf = make_filename(mdb, DB_MEDIA_FILENAME);
461 mdb->mediafd = fopen(dbf, "r+b");
463 Mmsg2(&mdb->errmsg, "Error opening DB Media file %s: ERR=%s\n",
464 dbf, strerror(errno));
474 void _db_lock(const char *file, int line, B_DB *mdb)
477 if ((errstat=rwl_writelock(&mdb->lock)) != 0) {
478 e_msg(file, line, M_ABORT, 0, "rwl_writelock failure. ERR=%s\n",
483 void _db_unlock(const char *file, int line, B_DB *mdb)
486 if ((errstat=rwl_writeunlock(&mdb->lock)) != 0) {
487 e_msg(file, line, M_ABORT, 0, "rwl_writeunlock failure. ERR=%s\n",
493 * Start a transaction. This groups inserts and makes things
494 * much more efficient. Usually started when inserting
497 void db_start_transaction(JCR *jcr, B_DB *mdb)
501 void db_end_transaction(JCR *jcr, B_DB *mdb)
505 bool db_update_storage_record(JCR *jcr, B_DB *mdb, STORAGE_DBR *sr)
509 db_list_pool_records(JCR *jcr, B_DB *mdb, POOL_DBR *pdbr,
510 DB_LIST_HANDLER *sendit, void *ctx, e_list_type type)
513 int db_int64_handler(void *ctx, int num_fields, char **row)
516 bool db_create_file_attributes_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
521 int db_create_file_item(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
528 * Create a new record for the Job
529 * This record is created at the start of the Job,
530 * it is updated in bdb_update.c when the Job terminates.
532 * Returns: 0 on failure
535 bool db_create_job_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr)
540 /* Create a JobMedia record for Volume used this job
541 * Returns: 0 on failure
542 * record-id on success
544 bool db_create_jobmedia_record(JCR *jcr, B_DB *mdb, JOBMEDIA_DBR *jm)
551 * Create a unique Pool record
552 * Returns: 0 on failure
555 bool db_create_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pr)
560 bool db_create_device_record(JCR *jcr, B_DB *mdb, DEVICE_DBR *dr)
563 bool db_create_storage_record(JCR *jcr, B_DB *mdb, STORAGE_DBR *dr)
566 bool db_create_mediatype_record(JCR *jcr, B_DB *mdb, MEDIATYPE_DBR *dr)
571 * Create Unique Media record. This record
572 * contains all the data pertaining to a specific
575 * Returns: 0 on failure
578 int db_create_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
583 int db_create_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cr)
588 bool db_create_fileset_record(JCR *jcr, B_DB *mdb, FILESET_DBR *fsr)
593 int db_create_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr)
596 bool db_write_batch_file_records(JCR *jcr) { return false; }
597 bool my_batch_start(JCR *jcr, B_DB *mdb) { return false; }
598 bool my_batch_end(JCR *jcr, B_DB *mdb, const char *error) { return false; }
599 bool my_batch_insert(JCR *jcr, B_DB *mdb, ATTR_DBR *ar) { return false; }
601 int db_delete_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pr)
606 int db_delete_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
611 bool db_find_job_start_time(JCR *jcr, B_DB *mdb, JOB_DBR *jr, POOLMEM **stime)
617 db_find_next_volume(JCR *jcr, B_DB *mdb, int item, bool InChanger, MEDIA_DBR *mr)
623 db_find_last_jobid(JCR *jcr, B_DB *mdb, const char *Name, JOB_DBR *jr)
627 db_find_failed_job_since(JCR *jcr, B_DB *mdb, JOB_DBR *jr, POOLMEM *stime, int &JobLevel)
630 bool db_get_job_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr)
635 int db_get_num_pool_records(JCR *jcr, B_DB *mdb)
640 int db_get_pool_ids(JCR *jcr, B_DB *mdb, int *num_ids, uint32_t *ids[])
643 bool db_get_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pr)
646 int db_get_num_media_records(JCR *jcr, B_DB *mdb)
649 bool db_get_media_ids(JCR *jcr, B_DB *mdb, uint32_t PoolId, int *num_ids, uint32_t *ids[])
652 bool db_get_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
655 int db_get_job_volume_names(JCR *jcr, B_DB *mdb, uint32_t JobId, POOLMEM **VolumeNames)
658 int db_get_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cr)
661 int db_get_fileset_record(JCR *jcr, B_DB *mdb, FILESET_DBR *fsr)
664 bool db_get_query_dbids(JCR *jcr, B_DB *mdb, POOL_MEM &query, dbid_list &ids)
667 int db_get_file_attributes_record(JCR *jcr, B_DB *mdb, char *fname, JOB_DBR *jr, FILE_DBR *fdbr)
670 int db_get_job_volume_parameters(JCR *jcr, B_DB *mdb, uint32_t JobId, VOL_PARAMS **VolParams)
673 int db_get_client_ids(JCR *jcr, B_DB *mdb, int *num_ids, uint32_t *ids[])
676 int db_get_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr)
679 int db_list_sql_query(JCR *jcr, B_DB *mdb, const char *query, DB_LIST_HANDLER *sendit,
680 void *ctx, int verbose)
683 void db_list_pool_records(JCR *jcr, B_DB *mdb, DB_LIST_HANDLER *sendit, void *ctx)
686 void db_list_media_records(JCR *jcr, B_DB *mdb, MEDIA_DBR *mdbr,
687 DB_LIST_HANDLER *sendit, void *ctx)
690 void db_list_jobmedia_records(JCR *jcr, B_DB *mdb, uint32_t JobId,
691 DB_LIST_HANDLER *sendit, void *ctx)
694 void db_list_job_records(JCR *jcr, B_DB *mdb, JOB_DBR *jr,
695 DB_LIST_HANDLER *sendit, void *ctx)
698 void db_list_job_totals(JCR *jcr, B_DB *mdb, JOB_DBR *jr,
699 DB_LIST_HANDLER *sendit, void *ctx)
702 void db_list_files_for_job(JCR *jcr, B_DB *mdb, uint32_t jobid, DB_LIST_HANDLER *sendit, void *ctx)
705 void db_list_client_records(JCR *jcr, B_DB *mdb, DB_LIST_HANDLER *sendit, void *ctx)
708 int db_list_sql_query(JCR *jcr, B_DB *mdb, const char *query, DB_LIST_HANDLER *sendit,
709 void *ctx, int verbose, e_list_type type)
715 db_list_pool_records(JCR *jcr, B_DB *mdb, DB_LIST_HANDLER *sendit, void *ctx, e_list_type type)
719 db_list_media_records(JCR *jcr, B_DB *mdb, MEDIA_DBR *mdbr,
720 DB_LIST_HANDLER *sendit, void *ctx, e_list_type type)
723 void db_list_jobmedia_records(JCR *jcr, B_DB *mdb, uint32_t JobId,
724 DB_LIST_HANDLER *sendit, void *ctx, e_list_type type)
728 db_list_job_records(JCR *jcr, B_DB *mdb, JOB_DBR *jr, DB_LIST_HANDLER *sendit,
729 void *ctx, e_list_type type)
733 db_list_client_records(JCR *jcr, B_DB *mdb, DB_LIST_HANDLER *sendit, void *ctx, e_list_type type)
736 bool db_update_job_start_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr)
742 * This is called at Job termination time to add all the
743 * other fields to the job record.
745 int db_update_job_end_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr, bool stats_enabled)
751 int db_update_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
756 int db_update_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pr)
761 int db_add_digest_to_file_record(JCR *jcr, B_DB *mdb, FileId_t FileId, char *digest, int type)
766 int db_mark_file_record(JCR *jcr, B_DB *mdb, FileId_t FileId, JobId_t JobId)
771 int db_update_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cr)
776 int db_update_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr)
781 int db_update_media_defaults(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
786 void db_make_inchanger_unique(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
792 #endif /* HAVE_BACULA_DB */