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