]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/cats/bdb.c
kes Cancel storage daemon in all cases where FD reports error. This
[bacula/bacula] / bacula / src / cats / bdb.c
1 /*
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
7  *  system.
8  *
9  *    Kern Sibbald, January MMI
10  *
11  *    Version $Id$
12  *
13  */
14 /*
15    Bacula® - The Network Backup Solution
16
17    Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
18
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
24    in the file LICENSE.
25
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.
30
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
34    02110-1301, USA.
35
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.
40 */
41
42
43 /* The following is necessary so that we do not include
44  * the dummy external definition of DB.
45  */
46 #define __SQL_C                       /* indicate that this is sql.c */
47
48 #include "bacula.h"
49 #include "cats.h"
50
51 #ifdef HAVE_BACULA_DB
52
53 uint32_t bacula_db_version = 0;
54
55 /* List of open databases */
56 static BQUEUE db_list = {&db_list, &db_list};
57 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
58
59 /* -----------------------------------------------------------------------
60  *
61  *   Bacula specific defines and subroutines
62  *
63  * -----------------------------------------------------------------------
64  */
65
66
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"
74
75 dbid_list::dbid_list() 
76 {
77    memset(this, 0, sizeof(dbid_list));
78    max_ids = 1000;
79    DBId = (DBId_t *)malloc(max_ids * sizeof(DBId_t));
80    num_ids = num_seen = tot_ids = 0;
81    PurgedFiles = NULL;
82 }
83
84 dbid_list::~dbid_list() 
85
86    free(DBId);
87 }
88
89 static POOLMEM *make_filename(B_DB *mdb, char *name)
90 {
91    char sep;
92    POOLMEM *dbf;
93
94    dbf = get_pool_memory(PM_FNAME);
95    if (IsPathSeparator(working_directory[strlen(working_directory)-1])) {
96       sep = 0;
97    } else {
98       sep = '/';
99    }
100    Mmsg(dbf, "%s%c%s-%s", working_directory, sep, mdb->db_name, name);
101    return dbf;
102 }
103
104 int bdb_write_control_file(B_DB *mdb)
105 {
106    mdb->control.time = time(NULL);
107    lseek(mdb->cfd, 0, SEEK_SET);
108    if (write(mdb->cfd, &mdb->control, sizeof(mdb->control)) != sizeof(mdb->control)) {
109       Mmsg1(&mdb->errmsg, "Error writing control file. ERR=%s\n", strerror(errno));
110       Emsg0(M_FATAL, 0, mdb->errmsg);
111       return 0;
112    }
113    return 1;
114 }
115
116 /*
117  * Retrieve database type
118  */
119 const char *
120 db_get_type(void)
121 {
122    return "Internal";
123 }
124
125 /*
126  * Initialize database data structure. In principal this should
127  * never have errors, or it is really fatal.
128  */
129 B_DB *
130 db_init_database(JCR *jcr, char const *db_name, char const *db_user, char const *db_password,
131                  char const *db_address, int db_port, char const *db_socket,
132                  int mult_db_connections)
133 {
134    B_DB *mdb;
135    P(mutex);                          /* lock DB queue */
136    /* Look to see if DB already open */
137    for (mdb=NULL; (mdb=(B_DB *)qnext(&db_list, &mdb->bq)); ) {
138       if (strcmp(mdb->db_name, db_name) == 0) {
139          Dmsg2(200, "DB REopen %d %s\n", mdb->ref_count, db_name);
140          mdb->ref_count++;
141          V(mutex);
142          return mdb;                  /* already open */
143       }
144    }
145
146    Dmsg0(200, "db_open first time\n");
147    mdb = (B_DB *)malloc(sizeof(B_DB));
148    memset(mdb, 0, sizeof(B_DB));
149    Dmsg0(200, "DB struct init\n");
150    mdb->db_name = bstrdup(db_name);
151    mdb->errmsg = get_pool_memory(PM_EMSG);
152    *mdb->errmsg = 0;
153    mdb->cmd = get_pool_memory(PM_EMSG);  /* command buffer */
154    mdb->ref_count = 1;
155    mdb->cached_path = get_pool_memory(PM_FNAME);
156    mdb->cached_path_id = 0;
157    qinsert(&db_list, &mdb->bq);       /* put db in list */
158    Dmsg0(200, "Done db_open_database()\n");
159    mdb->cfd = -1;
160    V(mutex);
161    Jmsg(jcr, M_WARNING, 0, _("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"));
162    Jmsg(jcr, M_WARNING, 0, _("WARNING!!!! The Internal Database is NOT OPERATIONAL!\n"));
163    Jmsg(jcr, M_WARNING, 0, _("You should use SQLite, PostgreSQL, or MySQL\n"));
164
165    return mdb;
166 }
167
168 /*
169  * Now actually open the database.  This can generate errors,
170  * which are returned in the errmsg
171  */
172 int
173 db_open_database(JCR *jcr, B_DB *mdb)
174 {
175    char *dbf;
176    int fd, badctl;
177    off_t filend;
178    int errstat;
179
180    Dmsg1(200, "db_open_database() %s\n", mdb->db_name);
181
182    P(mutex);
183
184    if ((errstat=rwl_init(&mdb->lock)) != 0) {
185       Mmsg1(&mdb->errmsg, _("Unable to initialize DB lock. ERR=%s\n"), strerror(errstat));
186       V(mutex);
187       return 0;
188    }
189
190    Dmsg0(200, "make_filename\n");
191    dbf = make_filename(mdb, DB_CONTROL_FILENAME);
192    mdb->cfd = open(dbf, O_CREAT|O_RDWR, 0600);
193    free_memory(dbf);
194    if (mdb->cfd < 0) {
195       Mmsg2(&mdb->errmsg, _("Unable to open Catalog DB control file %s: ERR=%s\n"),
196          dbf, strerror(errno));
197       V(mutex);
198       return 0;
199    }
200    Dmsg0(200, "DB open\n");
201    /* See if the file was previously written */
202    filend = lseek(mdb->cfd, 0, SEEK_END);
203    if (filend == 0) {                 /* No, initialize everything */
204       Dmsg0(200, "Init DB files\n");
205       memset(&mdb->control, 0, sizeof(mdb->control));
206       mdb->control.bdb_version = BDB_VERSION;
207       bdb_write_control_file(mdb);
208
209       /* Create Jobs File */
210       dbf = make_filename(mdb, DB_JOBS_FILENAME);
211       fd = open(dbf, O_CREAT|O_RDWR, 0600);
212       free_memory(dbf);
213       close(fd);
214
215       /* Create Pools File */
216       dbf = make_filename(mdb, DB_POOLS_FILENAME);
217       fd = open(dbf, O_CREAT|O_RDWR, 0600);
218       free_memory(dbf);
219       close(fd);
220
221       /* Create Media File */
222       dbf = make_filename(mdb, DB_MEDIA_FILENAME);
223       fd = open(dbf, O_CREAT|O_RDWR, 0600);
224       free_memory(dbf);
225       close(fd);
226
227       /* Create JobMedia File */
228       dbf = make_filename(mdb, DB_JOBMEDIA_FILENAME);
229       fd = open(dbf, O_CREAT|O_RDWR, 0600);
230       free_memory(dbf);
231       close(fd);
232
233       /* Create Client File */
234       dbf = make_filename(mdb, DB_CLIENT_FILENAME);
235       fd = open(dbf, O_CREAT|O_RDWR, 0600);
236       free_memory(dbf);
237       close(fd);
238
239       /* Create FileSet File */
240       dbf = make_filename(mdb, DB_FILESET_FILENAME);
241       fd = open(dbf, O_CREAT|O_RDWR, 0600);
242       free_memory(dbf);
243       close(fd);
244    }
245
246    Dmsg0(200, "Read control file\n");
247    badctl = 0;
248    lseek(mdb->cfd, 0, SEEK_SET);      /* seek to begining of control file */
249    if (read(mdb->cfd, &mdb->control, sizeof(mdb->control)) != sizeof(mdb->control)) {
250       Mmsg1(&mdb->errmsg, _("Error reading catalog DB control file. ERR=%s\n"), strerror(errno));
251       badctl = 1;
252    } else if (mdb->control.bdb_version != BDB_VERSION) {
253       Mmsg2(&mdb->errmsg, _("Error, catalog DB control file wrong version. "
254 "Wanted %d, got %d\n"
255 "Please reinitialize the working directory.\n"),
256          BDB_VERSION, mdb->control.bdb_version);
257       badctl = 1;
258    }
259    bacula_db_version = mdb->control.bdb_version;
260    if (badctl) {
261       V(mutex);
262       return 0;
263    }
264    V(mutex);
265    return 1;
266 }
267
268 void db_close_database(JCR *jcr, B_DB *mdb)
269 {
270    P(mutex);
271    mdb->ref_count--;
272    if (mdb->ref_count == 0) {
273       qdchain(&mdb->bq);
274       /*  close file descriptors */
275       if (mdb->cfd >= 0) {
276          close(mdb->cfd);
277       }
278       free(mdb->db_name);
279       if (mdb->jobfd) {
280          fclose(mdb->jobfd);
281       }
282       if (mdb->poolfd) {
283          fclose(mdb->poolfd);
284       }
285       if (mdb->mediafd) {
286          fclose(mdb->mediafd);
287       }
288       if (mdb->jobmediafd) {
289          fclose(mdb->jobmediafd);
290       }
291       if (mdb->clientfd) {
292          fclose(mdb->clientfd);
293       }
294       if (mdb->filesetfd) {
295          fclose(mdb->filesetfd);
296       }
297       rwl_destroy(&mdb->lock);
298       free_pool_memory(mdb->errmsg);
299       free_pool_memory(mdb->cmd);
300       free_pool_memory(mdb->cached_path);
301       free(mdb);
302    }
303    V(mutex);
304 }
305
306 void db_thread_cleanup()
307 { }
308
309
310 void db_escape_string(JCR *jcr, B_DB *db, char *snew, char *old, int len)
311 {
312    memset(snew, 0, len);
313    bstrncpy(snew, old, len);
314 }
315
316 char *db_strerror(B_DB *mdb)
317 {
318    return mdb->errmsg;
319 }
320
321 int db_sql_query(B_DB *mdb, char const *query, DB_RESULT_HANDLER *result_handler, void *ctx)
322 {
323    return 1;
324 }
325
326 /*
327  * Open the Jobs file for reading/writing
328  */
329 int bdb_open_jobs_file(B_DB *mdb)
330 {
331    char *dbf;
332
333    if (!mdb->jobfd) {
334       dbf = make_filename(mdb, DB_JOBS_FILENAME);
335       mdb->jobfd = fopen(dbf, "r+b");
336       if (!mdb->jobfd) {
337          Mmsg2(&mdb->errmsg, "Error opening DB Jobs file %s: ERR=%s\n",
338             dbf, strerror(errno));
339          Emsg0(M_FATAL, 0, mdb->errmsg);
340          free_memory(dbf);
341          return 0;
342       }
343       free_memory(dbf);
344    }
345    return 1;
346 }
347
348 /*
349  * Open the JobMedia file for reading/writing
350  */
351 int bdb_open_jobmedia_file(B_DB *mdb)
352 {
353    char *dbf;
354
355    if (!mdb->jobmediafd) {
356       dbf = make_filename(mdb, DB_JOBMEDIA_FILENAME);
357       mdb->jobmediafd = fopen(dbf, "r+b");
358       if (!mdb->jobmediafd) {
359          Mmsg2(&mdb->errmsg, "Error opening DB JobMedia file %s: ERR=%s\n",
360             dbf, strerror(errno));
361          Emsg0(M_FATAL, 0, mdb->errmsg);
362          free_memory(dbf);
363          return 0;
364       }
365       free_memory(dbf);
366    }
367    return 1;
368 }
369
370
371 /*
372  * Open the Pools file for reading/writing
373  */
374 int bdb_open_pools_file(B_DB *mdb)
375 {
376    char *dbf;
377
378    if (!mdb->poolfd) {
379       dbf = make_filename(mdb, DB_POOLS_FILENAME);
380       mdb->poolfd = fopen(dbf, "r+b");
381       if (!mdb->poolfd) {
382          Mmsg2(&mdb->errmsg, "Error opening DB Pools file %s: ERR=%s\n",
383             dbf, strerror(errno));
384          Emsg0(M_FATAL, 0, mdb->errmsg);
385          free_memory(dbf);
386          return 0;
387       }
388       Dmsg1(200, "Opened pool file %s\n", dbf);
389       free_memory(dbf);
390    }
391    return 1;
392 }
393
394 /*
395  * Open the Client file for reading/writing
396  */
397 int bdb_open_client_file(B_DB *mdb)
398 {
399    char *dbf;
400
401    if (!mdb->clientfd) {
402       dbf = make_filename(mdb, DB_CLIENT_FILENAME);
403       mdb->clientfd = fopen(dbf, "r+b");
404       if (!mdb->clientfd) {
405          Mmsg2(&mdb->errmsg, "Error opening DB Clients file %s: ERR=%s\n",
406             dbf, strerror(errno));
407          Emsg0(M_FATAL, 0, mdb->errmsg);
408          free_memory(dbf);
409          return 0;
410       }
411       free_memory(dbf);
412    }
413    return 1;
414 }
415
416 /*
417  * Open the FileSet file for reading/writing
418  */
419 int bdb_open_fileset_file(B_DB *mdb)
420 {
421    char *dbf;
422
423    if (!mdb->filesetfd) {
424       dbf = make_filename(mdb, DB_CLIENT_FILENAME);
425       mdb->filesetfd = fopen(dbf, "r+b");
426       if (!mdb->filesetfd) {
427          Mmsg2(&mdb->errmsg, "Error opening DB FileSet file %s: ERR=%s\n",
428             dbf, strerror(errno));
429          Emsg0(M_FATAL, 0, mdb->errmsg);
430          free_memory(dbf);
431          return 0;
432       }
433       free_memory(dbf);
434    }
435    return 1;
436 }
437
438
439
440 /*
441  * Open the Media file for reading/writing
442  */
443 int bdb_open_media_file(B_DB *mdb)
444 {
445    char *dbf;
446
447    if (!mdb->mediafd) {
448       dbf = make_filename(mdb, DB_MEDIA_FILENAME);
449       mdb->mediafd = fopen(dbf, "r+b");
450       if (!mdb->mediafd) {
451          Mmsg2(&mdb->errmsg, "Error opening DB Media file %s: ERR=%s\n",
452             dbf, strerror(errno));
453          free_memory(dbf);
454          return 0;
455       }
456       free_memory(dbf);
457    }
458    return 1;
459 }
460
461
462 void _db_lock(const char *file, int line, B_DB *mdb)
463 {
464    int errstat;
465    if ((errstat=rwl_writelock(&mdb->lock)) != 0) {
466       e_msg(file, line, M_ABORT, 0, "rwl_writelock failure. ERR=%s\n",
467            strerror(errstat));
468    }
469 }
470
471 void _db_unlock(const char *file, int line, B_DB *mdb)
472 {
473    int errstat;
474    if ((errstat=rwl_writeunlock(&mdb->lock)) != 0) {
475       e_msg(file, line, M_ABORT, 0, "rwl_writeunlock failure. ERR=%s\n",
476            strerror(errstat));
477    }
478 }
479
480 /*
481  * Start a transaction. This groups inserts and makes things
482  *  much more efficient. Usually started when inserting
483  *  file attributes.
484  */
485 void db_start_transaction(JCR *jcr, B_DB *mdb)
486 {
487 }
488
489 void db_end_transaction(JCR *jcr, B_DB *mdb)
490 {
491 }
492
493 bool db_update_storage_record(JCR *jcr, B_DB *mdb, STORAGE_DBR *sr)
494 { return true; }
495
496 void
497 db_list_pool_records(JCR *jcr, B_DB *mdb, POOL_DBR *pdbr, 
498                      DB_LIST_HANDLER *sendit, void *ctx, e_list_type type)
499 { }
500
501 int db_int64_handler(void *ctx, int num_fields, char **row)
502 { return 0; }
503
504
505 #endif /* HAVE_BACULA_DB */