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